Mar
12

ActionBarSherlock – Удобная реализация UI-паттерна ActionBar для Android-приложений – Часть I

Что-то пауза с постами у нас получается совсем нечеловеческая. Попробуем еще разок возобновить публикации.
И сегодня мы познакомимся с библиотекой, реализующей UI-паттерн Action Bar для Android-приложений.

Разработчики библиотеки позиционируют ее как расширение к Compatibility Library, которое для создания ActionBar использует нативную реализацию, если это поддерживается системой, или же вручную дублирует нужный функционал.

Библиотека является open-source проектом и доступна для загрузки на GitHub.

Начало

Начать пользоваться библиотекой довольно просто. Нужно сделать вот что:

  • Унаследовать активити от SherlockActivity (или SherlockListActivity)
  • Переопределить метод onCreateOptionsMenu() и в нем заполнить объект Menu информацией о кнопках
  • В onCreate() или в манифесте указать что используется тема Theme_Sherlock

В итоге код получится приблизительно таким:

package ru.mobiledeveloper.actionbarsherlocktest;

import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;

import android.os.Bundle;
import ru.mobiledeveloper.actionbarsherlocktest.R;

public class ActionBarSherlockTestActivity extends SherlockActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    	setTheme(R.style.Theme_Sherlock);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add("Save")
            .setIcon(R.drawable.ic_compose)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        menu.add("Search")
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | 
                MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        return true;
    }
}

В результате получим такой внешний вид окна приложения:

Режим действия

ActionBar Sherlock поддерживает возможность отображения контекстно-зависимого содержания. Такая возможность называется режим действий (ActionMode). режим действий можно использовать, например, для отображения контекстного “меню” при длинном нажатии на єлемент списка.
Для того, чтобі добавить возможность отображать режим действий в приложение, нужно сделать следующее:

  • Создать класс, производный от ActionMode.Callback
  • Реализовать в этом классе метод onCreateActionMode(), в котором добавить нужные команды.
  • Реализовать в этом классе метод onActionItemClicked(), в котором написать код, обрабатывающий нажатия на кнопки в ActionBar
  • Для перехода в режим действий вызвать метод startActionMode() и в качестве параметра передать ему объект выше указанного класса

В коде это выглядит приблизительно так:

public class ActionBarSherlockTestActivity extends SherlockActivity {
	
	ActionMode mMode;
	
	private final class ActionModeA implements ActionMode.Callback {

        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            menu.add("Save")
                .setIcon(R.drawable.ic_compose)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
            menu.add("Search")
                .setIcon(R.drawable.ic_search)
                .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
            return true;
        }

		public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
			// TODO Auto-generated method stub
			return false;
		}

		public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
			Toast.makeText(ActionBarSherlockTestActivity.this, 
                            "Got click: " + item, Toast.LENGTH_SHORT).show();
            mode.finish();
			return true;
		}

		public void onDestroyActionMode(ActionMode mode) {
			// TODO Auto-generated method stub
			
		}
        
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
    	setTheme(R.style.Theme_Sherlock);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button btnTest = (Button)findViewById(R.id.btnTest);
        if(btnTest != null) {
        	btnTest.setOnClickListener(new OnClickListener() {
				
				public void onClick(View v) {
					mMode = startActionMode(new ActionModeA());
				}
			});
        }
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add("Save")
            .setIcon(R.drawable.ic_compose)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        menu.add("Search")
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | 
                MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        return true;
    }
}

И в результате получаем такое:

Существует, также, возможность отображать ActionBar только в режиме Action Mode и скрывать ее в остальное время работы приложения. Для этого в onCreate() надо вызвать requestWindowFeature(Window.FEATURE_NO_TITLE).

Провайдеры действий

ActionBar Sherlock поддерживает работу с провайдерами действий (Action Provider), которые позволяют реализовать отображение собственных виджетов в ActionBar и добавить более гибкое взаимодействие с пользователем. Action Provier можно повторно использовать в нескольких активитях.
Есть две возможности указать Action Provider для элемента – прописать его в XML файле для пункта меню или указать в коде с помощью setActionProvider().
Рассмотрим реализацию Action Provider’а, который по нажатию на кнопку в ActionBar открывает системные настройки:

public static class SettingsActionProvider extends ActionProvider {
	private static final Intent sSettingsIntent = new Intent(Settings.ACTION_SETTINGS);

	private final Context mContext;

    public SettingsActionProvider(Context context) {
        super(context);
        mContext = context;
    }

    @Override
    public View onCreateActionView() {
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        View view = layoutInflater.inflate(R.layout.settings_action_provider, null);
        ImageButton button = (ImageButton) view.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                mContext.startActivity(sSettingsIntent);
            }
        });
        return view;
    }

    @Override
    public boolean onPerformDefaultAction() {
        mContext.startActivity(sSettingsIntent);
        return true;
    }
}
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Этот элемент будет отображен в ActionBar
    menu.add("Settings")
        .setActionProvider(new SettingsActionProvider(
        		ActionBarSherlockTestActivity.this))
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | 
        		MenuItem.SHOW_AS_ACTION_WITH_TEXT);
        
    // Этот элемент будет отображен в стандартном меню
    menu.add("Settings")
        .setActionProvider(new SettingsActionProvider(
        		ActionBarSherlockTestActivity.this))
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
    return true;
}

XML-файл для кнопки:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:focusable="true"
    android:addStatesFromChildren="true"
    android:background="?attr/actionBarItemBackground"
    style="?attr/actionButtonStyle">
    <ImageButton android:id="@+id/button"
        android:background="@drawable/ic_launcher_settings"
        android:layout_width="32dip"
        android:layout_height="32dip"
        android:layout_gravity="center"
        android:scaleType="fitCenter"
        android:adjustViewBounds="true" />
</LinearLayout>

После создания провайдера действий и добавления его к пунктам меню получим такое:

Collapsible Actions

Есть возможность, при нажатии на пункт меню, отображать собственный контрол на всю ширину ActionBar. Например, для поиска можно отображать текстовое поле. Сделать это можно, указав дайаут с помощью setActionView() и стиль MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW.

public boolean onCreateOptionsMenu(Menu menu) {
    boolean isLight = SampleList.THEME == R.style.Theme_Sherlock_Light;
    menu.add("Search")
        .setIcon(isLight ? R.drawable.ic_search_inverse : R.drawable.ic_search)
        .setActionView(R.layout.collapsible_edittext)
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | 
                MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
    return true;
}

При нажатии на пункт в ActionBar будет отображен контрол из XML файла collapsible_edittext.xml.

Полезные функции

Индикатор прогресса
Есть возможность отобразить индикатор прогресса в ActionBar. Такая возможность может быть полезна для отображения прогресса длительной операции. Сделать это можно с помощью метода setSupportProgressBarIndeterminateVisibility().
Оверлей
Можно отображать ActionBar поверх контента при скроллинге. Очень полезная возможность, например, при просмотре текстов. Перевести ActinBar в режим оверлея можно с помощью метода requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY).

Различные типы активитей

В ActionBar Sherlock помимо обычной активити есть классы для отображения активитей со списками, активитей настройки, диалогов.
SherlockPreferenceActivity
Этот класс используется для отображения окон настройки. Функционал аналогичен PreferenceActivity из Android SDK.

SherlockListActivity и SherlockExpandableListActivity
Это активити, производные от ListActivity и ExpandableListActivity соответственно, в которую добавлен функционал по работе с ActionBar.
Диалоги
Есть возможность отображать активити в виде диалогов. Для этого надо указать соответствующую тему в манифесте (необходимо указывать тему именно в манифесте).

<activity
    android:name=".Dialog"
    android:label="@string/dialog"
    android:theme="@style/Theme.Sherlock.Dialog">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="com.actionbarsherlock.sample.demos.EXAMPLE" />
    </intent-filter>
</activity>

На вид выглядит так:

Пара слов о навигации

В ActionBar Sherlock есть возможность организовать навигацию внутри приложения средствами ActionBar. Визуально получается очень приятный результат, например можно реализовать навигацию посредством выпадающего списка или вкладками или еще каким-либо способом, встроив контрол для навигации в ActionBar.

Более подробно реализацию навигации рассмотрим в следующей части статьи.

Еще интересные посты о программировании для мобильных устройств:

No Comments

Make A Comment

No comments yet.

Comments RSS Feed   TrackBack URL

Leave a comment

Please leave these two fields as-is:

top