Главная страница
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
qrcode

Программирование под Android. Для профессионалов


Скачать 19.35 Mb.
НазваниеПрограммирование под Android. Для профессионалов
АнкорBrayn Khardi Bill Fillips - Programmirovanie po.
Дата23.05.2017
Размер19.35 Mb.
Формат файлаpdf
Имя файлаBrayn_Khardi_Bill_Fillips_-_Programmirovanie_po.pdf
оригинальный pdf просмотр
ТипДокументы
#21061
страница28 из 55
КаталогОбразовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
1   ...   24   25   26   27   28   29   30   31   ...   55
Глава 18. Контекстные меню и режим контекстных действий
Листинг 18.3 (продолжение)
Bundle savedInstanceState) {
View v = super.onCreateView(inflater, parent, savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (mSubtitleVisible) {
getActivity().getActionBar().setSubtitle(R.string.subtitle);
}
}
ListView listView = (ListView)v.findViewById(android.R.id.list);
registerForContextMenu(listView);
return v;
}
Идентификатор ресурса android.R.id.list используется для получения экзем- пляра
ListView
, находящегося под управлением
ListFragment
. Класс
ListFragment также содержит метод getListView()
, но в onCreateView(…)
этот метод использо- ваться не может, потому что getListView()
возвращает null до возвращения из onCreateView(…)
Запустите приложение CriminalIntent, сделайте долгое нажатие на элементе списка и убедитесь в том, что на экране появляется контекстное меню с командой
Delete
Crime
Рис. 18.2. Контекстное меню появляется при долгом нажатии

Реализация контекстного меню
299
Реакция на действие
Для подключения команды меню нам понадобится метод, удаляющий объект пре- ступления из модели. В файле
CrimeLab.java добавьте метод deleteCrime(Crime)
Листинг 18.4. Добавление метода для удаления преступления (CrimeLab.java)
public void addCrime(Crime c) {
mCrimes.add(c);
}
public void deleteCrime(Crime c) {
mCrimes.remove(c);
}
Следующий шаг — обработка выбора команды меню в методе onContextItemSelec ted(MenuItem)
. У
MenuItem имеется идентификатор, представляющий выбранную команду. Однако знать, что пользователь хочет удалить преступление из списка, недостаточно. Необходимо знать, какое преступление нужно удалить.
Эту информацию можно получить вызовом метода getMenuInfo()
для
MenuItem
Метод возвращает экземпляр класса, реализующего интерфейс
ContextMenu.Con- textMenuInfo
В классе
CrimeListFragment добавьте реализацию onContextItemSelected(MenuItem)
, которая использует информацию меню и адаптер для определения того, на каком объекте
Crime было сделано долгое нажатие. Далее этот объект
Crime удаляется из модели.
Листинг 18.5. Прослушивание выбора команды контекстного меню (CrimeListFragment.java)
@Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
{
getActivity().getMenuInflater().inflate(R.menu.crime_list_item_context, menu);
}
@Override
public boolean onContextItemSelected(MenuItem item) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
int position = info.position;
CrimeAdapter adapter = (CrimeAdapter)getListAdapter();
Crime crime = adapter.getItem(position);
switch (item.getItemId()) {
case R.id.menu_item_delete_crime:
CrimeLab.get(getActivity()).deleteCrime(crime);
adapter.notifyDataSetChanged();
return true;
}
return super.onContextItemSelected(item);
}
В листинге 18.5 метод getMenuInfo()
возвращает экземпляр
AdapterView.Adapt- erContextMenuInfo
, потому что
ListView является субклассом
AdapterView
. Мы

300
Глава 18. Контекстные меню и режим контекстных действий преобразуем тип результата getMenuInfo()
и получаем подробную информацию о выбранном элементе списка, включая его позицию в наборе данных. Позиция используется для получения искомого объекта
Crime
Запустите приложение CriminalIntent, добавьте новое преступление и удалите его долгим нажатием. (Чтобы имитировать долгое нажатие в эмуляторе, удерживайте нажатой левую кнопку мыши до появления меню.)
Реализация режима контекстных действий
Код, написанный нами для удаления преступления из контекстного меню, будет работать на любом устройстве Android. Например, на рис. 18.2 показано контекстное меню на устройстве с Jelly Bean.
Тем не менее на новых устройствах для отображения контекстных действий реко- мендуется использовать долгое нажатие на представлении, выведенном на экран в режиме контекстных действий. Когда экран находится в режиме контекстных действий, элементы, определенные в контекстном меню, отображаются на кон- текстной панели действий, наложенной на обычную панель действий. Контекстные панели действий удобны тем, что они не загромождают экран.
Рис. 18.3. Контекстная панель действий появляется при долгом нажатии
Чтобы реализовать контекстную панель действий, необходимо написать специаль- ный код, отдельный от кода контекстного меню. Кроме того, код контекстной панели

Реализация режима контекстных действий
301
действий содержит классы и методы, недоступные в Froyo и Gingerbread, поэтому необходимо проследить за тем, чтобы в таких ситуациях этот код не вызывался.
Множественное выделение
Когда представление списка находится в режиме контекстных действий, вы можете включить режим множественного выделения элементов списка. Любое действие, выбранное на контекстной панели действий, будет применяться ко всем выделен- ным представлениям.
В методе
CrimeListFragment.onCreateView(…)
назначьте представлению списка режим
CHOICE_MODE_MULTIPLE_MODAL
. Используйте константы версии сборки для от- деления кода, регистрирующего
ListView
, от кода, назначающего режим выделения.
Листинг 18.6. Назначение режима выделения
@TargetApi(11)
@Override public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
View v = super.onCreateView(inflater, parent, savedInstanceState);
ListView listView = (ListView)v.findViewById(android.R.id.list);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// Контекстные меню для Froyo и Gingerbread
registerForContextMenu(listView);
} else {
// Контекстная панель действий для Honeycomb и выше
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
}
return v;
}
Методы обратного вызова режима действий
в представлении списка
Следующий шаг — назначение для
ListView слушателя, реализующего интерфейс
AbsListView.MultiChoiceModeListener
. Этот интерфейс содержит следующий метод, который вызывается при выделении или отмене выделения представления.
public abstract void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked)
Интерфейс
MultiChoiceModeListener реализует другой интерфейс —
ActionMode.
Callback
. Когда экран переходит в режим контекстных действий, создается экзем- пляр класса
ActionMode
, а методы
ActionMode.Callback вызываются в разных точках жизненого цикла
ActionMode
ActionMode.Callback содержит четыре обязательных метода:
public abstract boolean onCreateActionMode(ActionMode mode, Menu menu)

302
Глава 18. Контекстные меню и режим контекстных действий
Вызывается при создании
ActionMode
. Именно здесь заполняется ресурс контекст- ного меню, которое будет отображаться на контекстной панели действий.
public abstract boolean onPrepareActionMode(ActionMode mode, Menu menu)
Вызывается после onCreateActionMode(…)
и каждый раз, когда существующую контекстную панель действий необходимо актуализировать новыми данными.
public abstract boolean onActionItemClicked(ActionMode mode, MenuItem item)
Вызывается, когда пользователь выбирает действие. Здесь программируется об- работка контекстных действий, определенных в ресурсе меню.
public abstract void onDestroyActionMode(ActionMode mode)
Вызывается перед уничтожением
ActionMode из-за того, что пользователь отменил режим действий или выбранное действие было обработано. Реализация по умолча- нию снимает выделение с представления(-й). Вы также можете обновить фрагмент любой необходимой информацией о том, что произошло в режиме контекстных действий.
В методе
CrimeListFragment.onCreateView(…)
назначьте слушателя, реализующего
MultiChoiceModeListener для представления списка. В нашем случае что-то делать нужно только в методах onCreateActionMode(…)
и onActionItemClicked(ActionMode,
MenuItem)
Листинг 18.7. Назначение слушателя MultiChoiceModeListener (CrimeListFragment.java)
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listView.setMultiChoiceModeListener(new MultiChoiceModeListener() {
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
// Метод является обязательным, но не используется
// в этой реализации
}
// Методы ActionMode.Callback
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.crime_list_item_context, menu);
return true;
}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
// Метод является обязательным, но не используется
// в этой реализации
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_delete_crime:
CrimeAdapter adapter = (CrimeAdapter)getListAdapter();
CrimeLab crimeLab = CrimeLab.get(getActivity());
for (int i = adapter.getCount() - 1; i >= 0; i--) {

Реализация режима контекстных действий
303
if (getListView().isItemChecked(i)) {
crimeLab.deleteCrime(adapter.getItem(i));
}
}
mode.finish();
adapter.notifyDataSetChanged();
return true;
default:
return false;
}
}
public void onDestroyActionMode(ActionMode mode) {
// Метод является обязательным, но не используется
// в этой реализации
}
});
return v;
}
Если вы использовали функцию автозавершения Eclipse для создания этого интер- фейса, обратите внимание: заглушка, сгенерированная для onCreateActionMode(…)
, возвращает false
. Обязательно измените возвращаемое значение на true
; возвра- щение false отменяет создание режима действий.
В коде метода onCreateActionMode(…)
обратите внимание на то, что мы получаем экземпляр
MenuInflater от объекта
ActionMode
, а не от активности. Режим действий содержит подробную информацию для настройки контекстной панели действий.
Например, вызов
ActionMode.setTitle(…)
позволяет назначить контекстной панели действий специальный заголовок. Объект
MenuInflater активности не будет знать об этом заголовке.
Рис. 18.4. Второй и третий элемент списка выделены

304
Глава 18. Контекстные меню и режим контекстных действий
В методе onActionItemClicked(…)
мы удаляем один или несколько объектов
Crime из
CrimeLab
, а затем перезагружаем список для отражения внесенных изменений. Вы- зов
ActionMode.finish()
подготавливает объект режима действий к уничтожению.
Запустите приложение CriminalIntent. Сделайте долгое нажатие на элементе спи- ска, чтобы выделить его и войти в режим контекстных действий. Выберите другие элементы списка (обычным) нажатием. Снятие выделения с ошибочно выделенных элементов осуществляется так же. Удалите пару преступлений. Нажатие кнопки удаления завершает режим действий и возвращает приложение к обновленному списку преступлений.
Также можно отменить режим действий нажатием на значке у левого края панели контекстной панели действий. При этом режим действий завершается, а приложение возвращается к списку без внесения каких-либо изменений.
Хотя эта реализация работает, по внешнему виду списка трудно понять, какие элементы были выделены. Проблема решается изменением фона элементов списка при выделении.
Изменение фона выделенных элементов
Иногда представление должно изменяться в зависимости от своего текущего со- стояния. В нашем случае фон элемента списка должен изменяться при его переходе в активное состояние, чтобы привлечь внимание пользователя.
Изменение фона на основании состояния представления может осуществляться при помощи графической метки списка состояний. Такая метка представляет собой ресурс XML. В ресурсе указывается имя графической метки (растрового изобра- жения или цвета) и перечисляется список состояний, в которых эта метка должна отображаться. (Другие состояния, в которых может находиться представление, перечислены в документации
StateListDrawable
.)
В отличие от других графических ресурсов, графические метки списка состояний не связываются с плотностью пикселов, а следовательно, размещаются в каталоге drawable без уточнений. Создайте каталог res/drawable и новый файл XML с именем res/drawable/background_activated.xml
. Назначьте файлу корневой элемент selector и добавьте разметку, приведенную в листинге 18.8.
Листинг 18.8. Простая графическая метка списка состояний
(res/drawable/background_activated.xml)



android:state_activated="true"
android:drawable="@android:color/darker_gray"
/>

Эта разметка означает: «Когда представление, которое ссылается на эту графическую метку, находится в активном состоянии, использовать значение android:drawable
В противном случае ничего не делать». Если задать android:state_activated

Реализация режима контекстных действий в других представлениях
305
значение false
, то метка будет использоваться в тех случаях, когда представление
не находится
в активном состоянии.
Измените файл res/layout/list_item_crime.xml и включите в него ссылку на графическую метку.
Листинг 18.9. Изменение фона элемента списка (res/layout/list_item_crime.xml)
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/background_activated">

Снова запустите приложение CriminalIntent. На этот раз выделенные элементы будут сразу видны на общем фоне.
Рис. 18.5. Сразу видно, что второй и третий элемент списка выделены
О графических метках списков состояний более подробно рассказано в главе 25.
Реализация режима контекстных действий
в других представлениях
Реализация контекстной панели действий, использованная в этой главе, хоро- шо подходит для
ListView
. Она также будет работать с
GridView
— субклассом

306
Глава 18. Контекстные меню и режим контекстных действий
AdapterView
, который мы будем использовать в главе 26. Но что, если вам пона- добится контекстная панель действий для представления, которое не является ни
ListView
, ни
GridView
?
Прежде всего назначьте слушателя, реализующего
View.OnLongClickListener
В реализации этого слушателя создайте экземпляр
ActionMode вызовом
Activity.
startActionMode(…)
. (При использовании
MultiChoiceModeListener экземпляр
ActionMode создается за вас.)
Единственный параметр startActionMode(…)
содержит объект, реализующий интерфейс
ActionMode.Callback
. Вы создаете реализацию
ActionMode.Callback
, включающую четыре метода жизненного цикла
ActionMode
, которые были реали- зованы ранее:
public abstract boolean onCreateActionMode(ActionMode mode, Menu menu)
public abstract boolean onPrepareActionMode(ActionMode mode, Menu menu)
public abstract boolean onActionItemClicked(ActionMode mode, MenuItem item)
public abstract void onDestroyActionMode(ActionMode mode)
Либо создайте объект, реализующий
ActionMode.Callback
, и передайте его startAction-
Mode(…)
, либо передайте анонимную реализацию прямо в вызове startActionMode(…)
Совместимость: отход или дублирование?
В этой главе мы использовали стратегию совместимости, называемую корректным
отходом
(gracious fallback): приложение использует новые возможности и код на новых платформах и отходит к старой функциональности на старых устройствах.
Для этого мы проверяем версию SDK во время выполнения.
Корректный отход — не единственная стратегия. Вместо отхода к старым платфор- мам можно использовать идентичную функцию, имитирующую возможности новых платформ. Мы назовем эту стратегию дублированием (duplication).
Стратегии дублирования делятся на две группы: дублирование по необходимости и заменяющее дублирование. В первом случае замена производится только на старых платформах, на которых настоящая функциональность недоступна. Заменяющее дублирование используется постоянно — даже на платформах, на которых имеется собственная поддержка этой функциональности.
Использование библиотеки поддержки для работы с фрагментами — пример стра- тегии заменяющего дублирования. Ваши приложения всегда используют заменя- ющий класс android.support.v4.app.Fragment
— даже при запуске на устройствах, на которых класс android.app.Fragment доступен.
В библиотеке поддержки нет дубликата для панели действий, но существует целый ряд сторонних реализаций панели действий, которые могут использоваться для обеспечения совместимости на старых устройствах. Если приложение с панелью действий работает на телефоне с Gingerbread, значит, оно использует одну из сторонних библиотек. Самая лучшая и популярная из них — библиотека
Action-
BarSherlock
Джейка Уортона ( Jake Wharton) — см. https://www.actionbarsherlock.com.
Библиотека
ActionBarSherlock базируется на новейших исходных кодах Android

Для любознательных: ActionBarSherlock
307
и предоставляет поддержку дублирования по необходимости для функциональ- ности панелей действий во всех предыдущих версиях Android. Дополнительная информация о библиотеке
ActionBarSherlock и ее использовании приведена в раз- деле «Для любознательных» и втором упражнении в конце главы.
(Знающие люди говорят, что поддержка дубликатной панели действий появится и в библиотеке поддержки. Этот день для многих станет праздником.)
Какая стратегия лучше? У стратегий дублирования несомненные преимущества.
Главное заключается в том, что поведение кода остается неизменным независимо от используемой версии Android. Это относится в первую очередь к стратегиям заменяющего дублирования, при которых во всех версиях Android выполняется совершенно одинаковый код. Проектировщиков дублирование тоже устраивает, потому что им приходится планировать только один вариант пользовательского интерфейса. К ним присоединяются тестировщики, которым достаточно протести- ровать только один набор взаимодействий. Наконец, при стратегии дублирования ваше приложение выглядит как новая разработка для ICS или Jelly Bean еще до того, как пользователь выполнит обновление.
Впрочем, у стратегии дублирования есть два больших недостатка. Во-первых, чтобы ваше приложение имело современный вид, приходится полагаться на сторонние библиотеки. Собственно, именно по этой причине в книге для панели действий ис- пользовалась стратегия корректного отхода. Во-вторых, такое приложение может казаться чужеродным на фоне остальных приложений устройства. Если в вашем приложении используется собственный вариант дизайна, это не создаст проблем, поскольку оно все равно будет отличаться от других. Но если вы намеревались соблюдать стиль стандартных приложений вашего телефона, такое приложение будет выделяться, как бельмо на глазу.
Упражнение. Удаление из CrimeFragment
Пользователям будет удобно иметь возможность удалять преступления как из спи- ска, так и из представления детализации. В этом случае удаление будет применяться к экрану в целом, поэтому такое действие должно размещаться в командном меню или на панели действий. Реализуйте возможность удаления преступлений в
CrimeFragment
Для любознательных: ActionBarSherlock
Насколько бы важно ни было понимание принципов работы стандартных библи- отек Android и их поведения на разных устройствах и версиях ОС, на практике разработчики часто забывают об этих проблемах. Безусловно, больше всего про- блем с совместимостью создает панель действий, о которой было рассказано в этой главе и главе 16.
Библиотека
ActionBarSherlock
(или ABS, как ее чаще называют) предназначена исключительно для решения этих проблем. Она предоставляет реализацию панели действий для старых версий, а также набор классов, которые используют системную

308
1   ...   24   25   26   27   28   29   30   31   ...   55

перейти в каталог файлов

Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей

Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей