Главная страница
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 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
страница21 из 55
КаталогОбразовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
Образовательный портал Как узнать результаты егэ Стихи про летний лагерь 3агадки для детей
1   ...   17   18   19   20   21   22   23   24   ...   55
Глава 11. ViewPager уничтожается, но экземпляр фрагмента продолжает существовать в
FragmentMan- ager
. Таким образом, фрагменты, созданные
FragmentPagerAdapter
, никогда не уничтожаются.
Fragment
для Item1
Текущий фрагмент
Переход на страницу вправо
Представ- ление
Представ- ление
Представ- ление
Представ- ление
Представ- ление
Текущий фрагмент
Fragment
для Item2
Fragment
для Item3
Fragment
для Item1
Fragment
для Item2
Fragment
для Item3
Рис. 11.4. Управление фрагментами FragmentPagerAdapter
Выбор используемого адаптера зависит от приложения. Как правило,
Fragment-
StatePagerAdapter более экономно расходует память. Приложение CriminalIntent выводит список, который со временем может стать достаточно длинным, причем к каждому элементу списка может прилагаться фотография. Хранить всю эту инфор- мацию в памяти нежелательно, поэтому мы используем
FragmentStatePagerAdapter
С другой стороны, если интерфейс содержит небольшое фиксированное количество фрагментов, использование
FragmentPagerAdapter безопасно и уместно. Самый характерный пример такого рода — интерфейс с вкладками. Некоторые детализи- рованные представления не помещаются на одном экране, поэтому отображаемая информация распределяется между несколькими вкладками. Добавление
ViewPager с перебором вкладок делает этот интерфейс интуитивным. Хранение фрагментов в памяти упрощает управление кодом контроллера, а поскольку этот стиль интер- фейса обычно использует всего два или три фрагмента на активность, проблемы с нехваткой памяти крайне маловероятны.
Для любознательных: как работает ViewPager
Классы
ViewPager и
PagerAdapter незаметно выполняют большую часть рутинной работы. В этом разделе приведена более подробная информация о том, что при этом происходит.

Для любознательных: как работает ViewPager
221
Пара предупреждений, прежде чем мы перейдем к обсуждению: во-первых, согласно документации класс
ViewPager все еще находится в процессе разработки, так что интерфейсы могут измениться в будущем. Во-вторых, в большинстве случаев по- нимать все технические подробности не обязательно.
Но если вы захотите реализовать интерфейс
PagerAdapter самостоятельно, вы должны знать, чем отношения
ViewPager
-
PagerAdapter отличаются от обычных отношений
AdapterView
-
Adapter
Почему
ViewPager
, а не
AdapterView
? У
AdapterView имеется субкласс
Gallery с по- хожим поведением. Почему бы не использовать его?
Использование
AdapterView в данном случае потребует большого объема работы, потому что вы не сможете использовать существующие экземпляры
Fragment
Adapter ожидает, что вы сможете предоставить
View мгновенно. Но когда будет создано представление вашего фрагмента, решает
FragmentManager
, а не вы. Таким образом, когда
Gallery обратиться к
Adapter за представлением вашего фрагмента, вы не сможете создать фрагмент и немедленно выдать его представление.
Именно по этой причине и существует класс
ViewPager
. Вместо
Adapter он ис- пользует класс с именем
PagerAdapter
. Этот класс сложнее
Adapter
, потому что он выполняет больший объем работы по управлению представлениями. Ниже кратко перечислены основные различия.
Вместо метода getView(…)
, возвращающего представление,
PagerAdapter содержит следующие методы:
public Object instantiateItem(ViewGroup container, int position)
public void destroyItem(ViewGroup container, int position, Object object)
public abstract boolean isViewFromObject(View view, Object object)
Метод pagerAdapter.instantiateItem(ViewGroup,
int)
приказывает адаптеру создать представление элемента списка для заданной позиции и добавить его в контейнер
ViewGroup
; метод destroyItem(ViewGroup,
int,
Object)
приказывает уничтожить этот элемент. Обратите внимание: метод instantiateItem(ViewGroup,
int)
не приказывает создать представление немедленно.
PagerAdapter может создать представление в будущем.
После того как представление было создано,
ViewPager в какой-то момент заме- чает его. Чтобы понять, к какому элементу списка оно относится,
ViewPager вы- зывает метод isViewFromObject(View,
Object)
. Параметр
Object содержит объект, полученный при вызове instantiateItem(ViewGroup,
int)
. Таким образом, если
ViewPager вызывает instantiateItem(ViewGroup,
5)
и получает объект
A
, вызов isViewFromObject(View,
A)
должен вернуть true
, если переданный экземпляр
View относится к элементу 5, и false в противном случае.
Этот процесс достаточно сложен для
ViewPager
, но не для класса
PagerAdapter
, ко- торый должен уметь только создавать представления, уничтожать представления и определять, к какому объекту относится представление. Менее жесткие требо- вания позволяют реализации
PagerAdapter создавать и добавлять новый фрагмент в instantiateItem(ViewGroup,
int)
и возвращать фрагмент как отслеживаемый экземпляр
Object
. При этом isViewFromObject(View,
Object)
выглядит примерно так:

222
Глава 11. ViewPager
@Override public boolean isViewFromObject(View view, Object object) {
return ((Fragment)object).getView() == view;
}
Реализовать переопределения
PagerAdapter каждый раз, когда потребуется ис- пользовать
ViewPager
, было бы слишком утомительно. Хорошо, что у нас есть
FragmentPagerAdapter и
FragmentStatePagerAdapter

Диалоговые окна
Диалоговые окна требуют внимания пользователя и ввода данных. Обычно они ис- пользуются для принятия решений или отображения важной информации. В этой главе мы добавим диалоговое окно, в котором пользователь может изменить дату преступления.
При нажатии кнопки даты в
CrimeFragment открывается диалоговое окно, пока- занное на рис. 12.1.
Рис. 12.1. Диалоговое окно для выбора даты
12

224
Глава 12. Диалоговые окна
Диалоговое окно на рис. 12.1 является экземпляром
AlertDialog
— субкласса
Dia- log
. Именно этот многоцелевой субкласс
Dialog вы будете чаще всего использовать в своих программах.

AlertDialog существует субкласс
DatePickerDialog
, который вроде бы идеально подходит для наших целей. Однако на момент написания книги реализация
Dat- ePickerDialog работала с ошибками; использовать
AlertDialog проще, чем обходить эти ошибки.)
Экземпляр
AlertDialog на рис. 12.1 упакован в экземпляр
DialogFragment
— субкласса
Fragment
. Вообще говоря, экземпляр
AlertDialog может отображаться и без
DialogFragment
, но Android так поступать не рекомендует. Управление диалоговым окном из
FragmentManager открывает больше возможностей для его отображения.
Кроме того, «минимальный» экземпляр
AlertDialog исчезнет при повороте устрой- ства. С другой стороны, если экземпляр
AlertDialog упакован в фрагмент, после поворота диалоговое окно будет создано заново и появится на экране.
Для приложения CriminalIntent мы создадим субкласс
DialogFragment с именем
DatePickerFragment
. В коде
DatePickerFragment создается и настраивается экземпляр
AlertDialog
, отображающий виджет
DatePicker
. В качестве хоста
DatePickerFrag- ment используется экземпляр
CrimePagerActivity
На рис. 12.2 изображена схема этих отношений.
Представление
Модель
Контроллер
Рис. 12.2. Диаграмма объектов для двух фрагментов с хостом CrimePagerActivity

Создание DialogFragment
225
Наши первоочередные задачи:

создание класса
DatePickerFragment
;

построение
AlertDialog
;

вывод диалогового окна на экран с использованием
FragmentManager
Позднее в этой главе мы подключим виджет
DatePicker и организуем передачу необходимых данных между
CrimeFragment и
DatePickerFragment
Прежде чем браться за работу, добавьте строковый ресурс (листинг 12.1).
Листинг 12.1. Добавление строки для заголовка диалогового окна (values/strings.xml)

Solved?
Crimes
Date of crime:

Создание DialogFragment
Создайте новый класс с именем
DatePickerFragment и назначьте его суперклассом версию
DialogFragment из библиотеки поддержки: android.support.v4.app.Dia- logFragment
Класс
DialogFragment содержит следующий метод:
public Dialog onCreateDialog(Bundle savedInstanceState)
Экземпляр
FragmentManager активности-хоста вызывает этот метод в процессе вы- вода
DialogFragment на экран.
Добавьте в файл
DatePickerFragment.java реализацию onCreateDialog(…)
, которая создает
AlertDialog с заголовком и одной кнопкой
OK
. (Виджет
DatePicker мы добавим позднее.)
Листинг 12.2. Создание DialogFragment (DatePickerFragment.java)
public class DatePickerFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok, null)
.create();
}
}
В этой реализации используется класс
AlertDialog.Builder
, предоставляющий динамичный интерфейс для конструирования экземпляров
AlertDialog
Сначала мы передаем объект
Context конструктору
AlertDialog.Builder
, который возвращает экземпляр
AlertDialog.Builder

226
Глава 12. Диалоговые окна
Затем вызываются два метода
AlertDialog.Builder для настройки диалогового окна:
public AlertDialog.Builder setTitle(int titleId)
public AlertDialog.Builder setPositiveButton(int textId,
DialogInterface.OnClickListener listener)
Метод setPositiveButton(…)
получает строковый ресурс и объект, реализующий
DialogInterface.OnClickListener
. В листинге 12.2 передается константа Android для кнопки
OK
и null вместо слушателя. Слушатель будет реализован позднее в этой главе.
Положительная кнопка (
Positive
) нажимается пользователем для подтверждения информации в диалоговом окне. В
AlertDialog также можно добавить еще две кнопки: отрицательную (
Negative
) и нейтральную (
Neutral
). Эти обозначения определяют позицию кнопок в диалоговом окне (если их несколько). На устрой- ствах Froyo и Gingerbread положительной является левая кнопка. На более новых устройствах порядок кнопок изменен, и положительной является правая кнопка).
Построение диалогового окна завершается вызовом
AlertDialog.Builder.create()
, который возвращает настроенный экземпляр
AlertDialog
На этом возможности
AlertDialog и
AlertDialog.Builder не исчерпаны; подроб- ности достаточно хорошо изложены в документации разработчика. А пока давайте перейдем к механике вывода диалогового окна на экран.
Отображение DialogFragment
Как и все фрагменты, экземпляры
DialogFragment находятся под управлением экземпляра
FragmentManager активности-хоста.
Для добавления экземпляра
DialogFragment в
FragmentManager и вывода его на экран используются следующие методы экземпляра фрагмента:
public void show(FragmentManager manager, String tag)
public void show(FragmentTransaction transaction, String tag)
Строковый параметр однозначно идентифицирует
DialogFragment в списка
Frag- mentManager
. Выбор версии (с
FragmentManager или
FragmentTransaction
) зависит только от вас — если передать
FragmentManager
, транзакция будет автоматически создана и закреплена. В нашем примере передается
FragmentManager
Добавьте в
CrimeFragment константу для метки
DatePickerFragment
. Затем в методе onCreateView(…)
удалите код, блокирующий кнопку даты, и назначьте слушателя
View.OnClickListener
, который отображает
DatePickerFragment при нажатии кнопки даты.
Листинг 12.3. Отображение DialogFragment (CrimeFragment.java)
public class CrimeFragment extends Fragment {
public static final String EXTRA_CRIME_ID =
"com.bignerdranch.android.criminalintent.crime_id";
private static final String DIALOG_DATE = "date";

Создание DialogFragment
227
@Override public View onCreateView(LayoutInflater inflater, ViewGroup parent,
Bundle savedInstanceState) {
mDateButton = (Button)v.findViewById(R.id.crime_date);
mDateButton.setText(mCrime.getDate().toString());
mDateButton.setEnabled(false);
mDateButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fm = getActivity()
.getSupportFragmentManager();
DatePickerFragment dialog = new DatePickerFragment();
dialog.show(fm, DIALOG_DATE);
}
});
mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);
return v;
}
}
Запустите приложение CriminalIntent и нажмите кнопку даты, чтобы диалоговое окно появилось на экране. Кнопка
OK
закрывает диалоговое окно (рис. 12.3).
Рис. 12.3. AlertDialog с заголовком и кнопкой

228
Глава 12. Диалоговые окна
Назначение содержимого диалогового окна
Далее мы включим в
AlertDialog виджет
DatePicker при помощи метода
Alert-
Dialog.Builder
:
public AlertDialog.Builder setView(View view)
Метод настраивает диалоговое окно для отображения переданного объекта
View между заголовком и кнопкой(-ами).
В
Package
Explorer создайте новый файл макета с именем dialog_date.xml и назначьте его корневым элементом
DatePicker
. Макет будет состоять из одного объекта
View
(
DatePicker
), который мы заполним и передадим setView(…)
Настройте макет
DatePicker так, как показано на рис. 12.4.
Рис. 12.4. Макет DatePicker (layout/dialog_date.xml)
В методе
DatePickerFragment.onCreateDialog(…)
заполните представление и на- значьте его диалоговому окну.
Листинг 12.4. Включение DatePicker в AlertDialog (DatePickerFragment.java)
@Override public Dialog onCreateDialog(Bundle savedInstanceState) {
View v = getActivity().getLayoutInflater()
.inflate(R.layout.dialog_date, null);
return new AlertDialog.Builder(getActivity())
.setView(v)
.setTitle(R.string.date_picker_title)
.setPositiveButton(android.R.string.ok, null)
.create();
}
Запустите приложение CriminalIntent. Нажмите кнопку даты и убедитесь в том, что в диалоговом окне теперь отображается
DatePicker
Почему мы возимся с определением и заполнением макета, когда объект
DatePicker можно было бы создать в коде так, как показано ниже?
@Override public Dialog onCreateDialog(Bundle savedInstanceState) {
DatePicker dp = new DatePicker(getActivity());
return new AlertDialog.Builder(getActivity())
.setView(dp)
.create();
}

Создание DialogFragment
229
Рис. 12.5. AlertDialog с DatePicker
Использование макета упрощает изменения в случае изменения его содержимого.
Предположим, вы захотели, чтобы рядом с
DatePicker в диалоговом окне отобра- жался виджет
TimePicker
. При использовании заполнения можно просто обновить файл макета, и новое представление появится на экране.
Итак, наше диалоговое окно успешно отображается. В следующем разделе мы свяжем его с полем даты
Crime и позаботимся о том, чтобы пользователь мог вводить данные.
Передача данных между фрагментами
Мы передавали данные между двумя активностями; мы передавали данные между двумя фрагментными активностями. Теперь нужно передать данные между дву- мя фрагментами, хостом которых является одна активность —
CrimeFragment и
DatePickerFragment
(см. рис. 5.10).
Чтобы передать дату преступления
DatePickerFragment
, мы напишем метод newInstance(Date)
и сделаем объект
Date аргументом фрагмента.
Чтобы вернуть новую дату фрагменту
CrimeFragment для обновления уровня модели и его собственного представления, мы упакуем ее как дополнение объекта
Intent и передадим этот объект
Intent в вызове
CrimeFragment.onActivityResult(…)
Вызов
Fragment.onActivityResult(…)
может показаться странным — с учетом того, что активность-хост не получает вызова
Activity.onActivityResult(…)
в этом взаимодействии. Но как будет показано позднее в этой главе, использование on-
ActivityResult(…)
для передачи данных от одного фрагмента к другому не только работает, но и улучшает гибкость отображения фрагмента диалогового окна.

230
Глава 12. Диалоговые окна
Дата, выбранная пользователем
Отображаемая дата
Рис. 12.6. Взаимодействие между CrimeFragment и DatePickerFragment
Рис. 12.7. Последовательность событий взаимодействия между CrimeFragment и DatePickerFragment
Передача данных DatePickerFragment
Чтобы получить данные в
DatePickerFragment
, мы сохраним дату в пакете аргумен- тов
DatePickerFragment
, где
DatePickerFragment сможет обратиться к ней.
Создание аргументов фрагмента и присваивание им значений обычно выполняет- ся в методе newInstance()
, заменяющем конструктор фрагмента. Добавьте в файл
DatePickerFragment.java метод newInstance(Date)
Листинг 12.5. Добавление метода newInstance(Date) (DatePickerFragment.java)
public class DatePickerFragment extends DialogFragment {
public static final String EXTRA_DATE =
"com.bignerdranch.android.criminalintent.date";
private Date mDate;
public static DatePickerFragment newInstance(Date date) {
Bundle args = new Bundle();
args.putSerializable(EXTRA_DATE, date);

Создание DialogFragment
231
DatePickerFragment fragment = new DatePickerFragment();
fragment.setArguments(args);
return fragment;
}
}
В классе
CrimeFragment удалите вызов конструктора
DatePickerFragment и замените его вызовом
DatePickerFragment.newInstance(Date)
Листинг 12.6. Добавление вызова newInstance() (CrimeFragment.java)
@Override public View onCreateView(LayoutInflater inflater,
ViewGroup parent, Bundle savedInstanceState) {
mDateButton = (Button)v.findViewById(R.id.crime_date);
updateDate();
mDateButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentManager fm = getActivity()
.getSupportFragmentManager();
D
1   ...   17   18   19   20   21   22   23   24   ...   55

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

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

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