- Фрагменты
- Основные классы
- FragmentManager
- Методы транзакции
- Аргументы фрагмента
- Управление стеком фрагментов
- Интеграция Action Bar/Options Menu
- Связь между фрагментом и активностью
- Android studio menu fragment
- Меню выбора опций (Options Menu)
- Создание меню при помощи ресурсов
- Выбор пунктов меню
- Программное создание меню
- Горячие клавиши
- Создание подменю
- Добавление флажков и переключателей
- Программное открытие или закрытие меню
- Программное удаление пункта меню
- Определить наличие кнопки Menu
- Разметка для меню
- Меню в фрагментах
Фрагменты
Существует два основных подхода в использовании фрагментов.
Первый способ основан на замещении родительского контейнера. Создаётся стандартная разметка и в том месте, где будут использоваться фрагменты, размещается контейнер, например, FrameLayout. В коде контейнер замещается фрагментом. При использовании подобного сценария в разметке не используется тег fragment, так как его нельзя менять динамически. Также вам придётся обновлять ActionBar, если он зависит от фрагмента. Здесь показан такой пример.
Второй вариант — используются отдельные разметки для телефонов и планшетов, которые можно разместить в разных папках ресурсов. Например, если в планшете используется двухпанельная разметка с двумя фрагментами на одной активности, мы используем эту же активность для телефона, но подключаем другую разметку, которая содержит один фрагмент. Когда нам нужно переключиться на второй фрагмент, то запускаем вторую активность.
Второй подход является наиболее гибким и в целом предпочтительным способом использования фрагментов. Активность проверяет в каком режиме (свои размеры) он запущен и использует разную разметку из ресурсов. Графически это выглядит следующим образом.
Основные классы
Сами фрагменты наследуются от androidx.fragment.app.Fragment. Существует подклассы фрагментов: ListFragment, DialogFragment, PreferenceFragment, WebViewFragment и др. Не исключено, что число классов будет увеличиваться, например, появился ещё один класс MapFragment.
Для взаимодействия между фрагментами используется класс android.app.FragmentManager — специальный менеджер по фрагментам.
Как в любом офисе, спецманагер не делает работу своими руками, а использует помощников. Например, для транзакций (добавление, удаление, замена) используется класс-помощник android.app.FragmentTransaction.
Для сравнения приведу названия классов из библиотеки совместимости:
- android.support.v4.app.FragmentActivity
- android.support.v4.app.Fragment
- android.support.v4.app.FragmentManager
- android.support.v4.app.FragmentTransaction
Как видите, разница в одном классе, который я привёл первым. Он используется вместо стандартного Activity, чтобы система поняла, что придётся работать с фрагментами. На данный момент студия создаёт проект на основе ActionBarActivity, который является подклассом FragmentActivity.
В одном приложении нельзя использовать новые фрагменты и фрагменты из библиотеки совместимости.
В 2018 году Гугл объявила фрагменты из пакета androd.app устаревшими. Заменяйте везде на версию из библиотеки совместимости. В 2020 году уже используют пакет androidx.fragment.app.
В версии Support Library 27.1.0 появились новые методы requireActivity() и requireContext(), которые пригодятся при написании кода, когда требуется наличие активности и нужно избежать ошибки на null.
Общий алгоритм работы с фрагментами будет следующим:
У каждого фрагмента должен быть свой класс. Класс наследуется от класса Fragment или схожих классов, о которых говорилось выше. Это похоже на создание новой активности или нового компонента.
Также, как в активности, вы создаёте различные методы типа onCreate() и т.д. Если фрагмент имеет разметку, то используется метод onCreateView() — считайте его аналогом метода setContentView(), в котором вы подключали разметку активности. При этом метод onCreateView() возвращает объект View, который является корневым элементом разметки фрагмента.
Разметку для фрагмента можно создать программно или декларативно через XML.
Создание разметки для фрагмента ничем не отличается от создания разметки для активности. Вот отрывок кода из метода onCreateView():
Глядя на этот код, вы должные понять, что фрагмент использует разметку из файла res/layout/first_fragment.xml, которая содержит кнопку с идентификатором android:id=»@+id/button_first». Здесь также прослеживается сходство с подключением компонентов в активности. Обратите внимание, что перед методом findViewById() используется view, так как этот метод относится к компоненту, а не к активности, как мы обычно делали в программах, когда просто опускали имя активности. Т.е. в нашем случае мы ищем ссылку на кнопку не среди разметки активности, а внутри разметки самого фрагмента.
Нужно помнить, что в методе inflate() последний параметр должен иметь значение false в большинстве случаев.
FragmentManager
Класс FragmentManager имеет два метода, позволяющих найти фрагмент, который связан с активностью:
findFragmentById(int id) Находит фрагмент по идентификатору findFragmentByTag(String tag) Находит фрагмент по заданному тегу
Методы транзакции
Мы уже использовали некоторые методы класса FragmentTransaction. Познакомимся с ними поближе
add() Добавляет фрагмент к активности remove() Удаляет фрагмент из активности replace() Заменяет один фрагмент на другой hide() Прячет фрагмент (делает невидимым на экране) show() Выводит скрытый фрагмент на экран detach() (API 13) Отсоединяет фрагмент от графического интерфейса, но экземпляр класса сохраняется attach() (API 13) Присоединяет фрагмент, который был отсоединён методом detach()
Методы remove(), replace(), detach(), attach() не применимы к статичным фрагментам.
Перед началом транзакции нужно получить экземпляр FragmentTransaction через метод FragmentManager.beginTransaction(). Далее вызываются различные методы для управления фрагментами.
В конце любой транзакции, которая может состоять из цепочки вышеперечисленных методов, следует вызвать метод commit().
Аргументы фрагмента
Фрагменты должны сохранять свою модульность и не должны общаться друг с другом напрямую. Если один фрагмент хочет докопаться до другого, он должен сообщить об этом своему менеджеру активности, а он уже передаст просьбу другому фрагменту. И наоборот. Это сделано специально для того, чтобы было понятно, что менеджер тут главный и он не зря зарплату получает. Есть три основных способа общения фрагмента с активностью.
- Активность может создать фрагмент и установить аргументы для него
- Активность может вызвать методы экземпляра фрагмента
- Фрагмент может реализовать интерфейс, который будет использован в активности в виде слушателя
Фрагмент должен иметь только один пустой конструктор без аргументов. Но можно создать статический newInstance с аргументами через метод setArguments().
Доступ к аргументам можно получить в методе onCreate() фрагмента:
Динамически загружаем фрагмент в активность.
Если активность должна выполнить какую-то операцию в фрагменте, то самый простой способ — задать нужный метод в фрагменте и вызвать данный метод через экземпляр фрагмента.
Вызываем метод в активности:
Если фрагмент должен сообщить о своих действиях активности, то следует реализовать интерфейс.
Управление стеком фрагментов
Фрагменты, как и активности, могут управляться кнопкой Back. Вы можете добавить несколько фрагментов, а потом через кнопку Back вернуться к первому фрагменту. Если в стеке не останется ни одного фрагмента, то следующее нажатие кнопки закроет активность.
Чтобы добавить транзакцию в стек, вызовите метод FragmentTransaction.addToBackStack(String) перед завершением транзакции (commit). Строковый аргумент — опциональное имя для идентификации стека или null. Класс FragmentManager имеет метод popBackStack(), возвращающий предыдущее состояние стека по этому имени.
Если вы вызовете метод addToBackStack() при удалении или замещении фрагмента, то будут вызваны методы фрагмента onPause(), onStop(), onDestroyView().
Когда пользователь нажимает на кнопку возврата, то вызываются методы фрагмента onCreateView(), onActivityCreated(), onStart() и onResume().
Рассмотрим пример реагирования на кнопку Back в фрагменте без использования стека. Активность имеет метод onBackPressed(), который реагирует на нажатие кнопки. Мы можем в этом методе сослаться на нужный фрагмент и вызвать метод фрагмента.
Теперь в классе фрагмента прописываем метод с нужным кодом.
Более желательным вариантом является использование интерфейсов. В некоторых примерах с фрагментами такой приём используется.
Интеграция Action Bar/Options Menu
Фрагменты могут добавлять свои элементы в панель действий или меню активности. Сначала вы должны вызвать метод Fragment.setHasOptionsMenu() в методе фрагмента onCreate(). Затем нужно задать настройки для методов фрагмента onCreateOptionsMenu() и onOptionsItemSelected(), а также при необходимости для методов onPrepareOptionsMenu(), onOptionsMenuClosed(), onDestroyOptionsMenu(). Работа методов фрагмента ничем не отличается от аналогичных методов для активности.
В активности, которая содержит фрагмент, данные методы автоматически сработают.
Если активность содержит собственные элементы панели действий или меню, то следует позаботиться, чтобы они не мешали вызовам методам фрагментов.
Код для активности:
Код для фрагмента:
Связь между фрагментом и активностью
Экземпляр фрагмента связан с активностью. Активность может вызывать методы фрагмента через ссылку на объект фрагмента. Доступ к фрагменту можно получить через методы findFragmentById() или findFragmentByTag().
Источник
Android studio menu fragment
Статья проплачена кошками — всемирно известными производителями котят.
Если статья вам понравилась, то можете поддержать проект.
Вы уже работали с меню в одном из первых уроков первого месяца обучения. Рассмотрим работу с меню глубже. Будут рассмотрены как старые устройства под Android 2.3, так и новые телефоны на Android 4.0.
Меню выбора опций (Options Menu)
За меню отвечает класс android.view.Menu. Каждая активность связана с одним объектом меню. Само меню содержит пункты меню (класс android.view.MenuItem) и подменю (класс android.view.SubMenu).
При нажатии кнопки Menu на старых телефонах появляется набор пунктов меню, прикрепляемый к активности. Меню может содержать значки. Такое меню может содержать шесть пунктов (как правило). При наличии более шести пунктов используется расширенное меню — в этом случае вместо шестого пункта появляется пункт Опции (More). При нажатии данного пункта показывается расширенное меню со списком пунктов, которые не поместились в основной части меню выбора опций.
Когда меню открывается впервые, Android вызывает метод onCreateOptionsMenu(), передавая в качестве параметра объект Menu. Меню можно создавать в виде ресурсов в XML-файле или использовать метод add().
В стандартном проекте при выборе обычного шаблона уже есть заготовка для меню из одного пункта Settings и вызов метода для меню (вы об этом уже знаете).
Создание меню при помощи ресурсов
Рассмотрим работу с меню через ресурсы. Для создания меню используются ресурсы, которые должны храниться в XML-файле. Сам файл должен находиться в папке res/menu/ вашего проекта. Меню состоит из следующих элементов:
Определяет меню, которое будет содержать пункты меню. Элемент должен быть корневым элементом в XML-структуре файла и может содержать один или несколько элементов и Создает непосредственно пункты меню. Данный элемент может иметь вложенный элемент для создания подменю При желании можете также использовать невидимый контейнер для элементов . Это позволяет достичь некоторых эффектов
Предположим, мы решили использовать меню для какой-нибудь игры. Создадим новый файл game_menu.xml:
Мы создали меню с двумя пунктами. Каждый пункт включает в себя следующие атрибуты:
android:id Идентификатор пункта меню, по которому приложение может распознать при выделении пункта меню пользователем android:title Текст, который будет выводиться в меню
Существуют и другие атрибуты для элемента item, например android:icon=»@drawable/home» позволит также вывести значок для пункта меню, а android:enabled=»false» позволяет сделать пункт меню недоступным.
Атрибут android:titleCondensed применяется в том случае, если обычный заголовок слишком широкий и не «помещается» в выбранном элементе меню.
Атрибут android:orderInCategory определяет порядок, в котором отображаются элементы меню MenuItems.
Кстати, вы можете использовать встроенные системные значки Android. Например, android:icon=»@android:drawable/ic_menu_help» позволит вам вывести значок помощи, который зашит в систему. Подробнее о системных значках почитайте в статье Системные графические ресурсы
При создании меню мы указали на строковые ресурсы @string/new_game и @string/help. Необходимо добавить новые строки в файле strings.xml:
Теперь нужно внести изменения в классе активности, в котором будет выводиться меню. Программа должна сконвертировать созданный нами ресурс меню в программный объект. Для этой цели существует специальный метод MenuInflater.inflate(), который вызывается в специальном методе обратного вызова onCreateOptionsMenu(). Данный метод и предназначен для вывода меню при нажатии кнопки MENU на устройстве:
После вставки кода среда разработки попросит импортировать недостающие пространства имен.
Метод onCreateOptionsMenu() метод инициирует первое появление меню на экране и принимает в качестве параметра объект Menu (для старых устройств). Вы можете сохранить ссылку на меню и использовать ее в любом месте кода, пока метод onCreateOptionsMenu() опять не будет вызван. Вам необходимо всегда использовать реализацию этого обработчика из родительского класса, потому как она при необходимости автоматически включает в меню дополнительные системные пункты. В новых устройствах метод вызывается при создании активности. Метод должен возвращать значение true, чтобы меню было видимым на экране.
Запустив программу, нажмите кнопку MENU на эмуляторе, чтобы увидеть созданное меню.
Метод getMenuInflater() возвращает экземпляр класса MenuInflater, который мы используем для чтения данных меню из XML.
Как видите, меню появляется в нижней части экрана. Всего можно одновременно вывести на экран шесть пунктов меню. Если пунктов больше, то будет выведено пять пунктов плюс шестой пункт More, который позволит увидеть остальные пункты. Давайте проверим и добавим новые пункты меню.
Сначала добавим шесть пунктов.
Добавим еще один пункт к меню, чтобы их стало семь.
Выбор пунктов меню
Мы научились создавать меню. Но пока оно бесполезно, так как пункты меню никак не реагируют на наши нажатия. Для обработки нажатий пунктов меню служит метод onOptionsItemSelected(). Метод распознает пункт, выбранный пользователем, через MenuItem. Мы можем теперь определить выбранный пункт через вызов getItemId(), который возвращает идентификатор пункта меню. Далее через оператор switch нам остается определить нужные команды:
Запустите приложение, вызовите меню и выберите первый или второй пункт меню. В текстовом поле должно появиться сообщение.
В приведенном примере getItemId() запрашивает ID для выбранного пункта меню и начинает сравнивать через оператор выбора switch с идентификаторами, которые мы задали в XML-ресурсах. При обнаружении нужного идентификатора выполняется обработчик для заданного пункта меню. Если программа ничего не обнаружит, то выполняется оператор default, который возвращает super class.
В Android 3.0 можно добавить атрибут android:onClick в ресурсах меню, и вам уже не нужно использовать onOptionsItemSelected(). При помощи android:onClick вы можете указать нужный метод при выборе пункта меню.
Программное создание меню
Рассмотрим программное создание меню для полноты картины. Нам понадобится определить несколько констант для пунктов меню:
У метода add() есть четыре параметра:
- идентификатор группы — позволяет связывать пункт меню с группой других пунктов этого меню
- идентификатор пункта для обработчика события выбора пункта меню
- порядок расположения пункта в меню — позволяет определять позицию в меню. По умолчанию (Menu.NONE или 0) пункты идут в том порядке, как задано в коде
- заголовок — текст, который выводится в пункте меню. Можно использовать строковый ресурс
Метод возвращает объект MenuItem, который можно использовать для установки дополнительных свойств, например, для установить значок, горячую клавишу и т.д.
Если вы хотите создать меню со значками, то воспользуйтесь методом setIcon()
Напомним еще раз, что значки можно добавить только к шести пунктам меню (или к пяти, если пунктов больше шести).
Метод onCreateOptionsMenu вызывается системой только один раз при создании меню. Если вам требуется обновить меню во время работы программы, то используйте метод обратного вызова onPrepareOptionsMenu().
При выборе пункта меню вызывается метод onOptionsItemSelected, который передает объект MenuItem — пункт меню, выбранный пользователем. При помощи метода getItemId можно получить идентификатор выбранного пункта меню. После идентификации пункта меню можно написать код для обработки события выбора меню:
Горячие клавиши
Также можно задавать горячие клавиши для быстрого доступа, используя символы клавиатуры, при помощи нескольких методов:
- setAlphabeticShortcut(char) — добавляет символ
- setNumericShortcut(int) — добавляет число
- setShortcut(char, int) — добавляет комбинацию символа и числа
Например, если задать горячую клавишу setAlphabeticShortcut(‘q’);, то при открытии меню (или при удерживании клавиши MENU) нажатие клавиши Q выберет данный пункт меню. Эта горячая клавиша (или сочетание клавиш) будет показана как подсказка, отображающая ниже имени пункта меню. В новых клавиатурах есть отдельная клавиша Ctrl, которая работает также, как на обычных клавиатурах.
Горячие клавиши можно создать и через XML: android:alphabeticShortcut=»c».
Обрабатывать нажатия можно через метод активности onKeyShortcut():
Создание подменю
Подменю можно добавить в любое меню, кроме другого подменю. Подменю создается в методе обратного вызова onCreateOptionsMenu() с помощью метода addSubMenu(), который возвращает объект SubMenu. В объект SubMenu можно добавить дополнительные пункты к этому меню, используя метод add(). Например:
Теперь при выборе пункта меню появится еще одно окно с подменю. Попробуйте сами.
Добавление флажков и переключателей
В пункты меню возможно добавление флажков или переключателей. Чтобы добавить флажок или переключатель для отдельного элемента меню, необходимо использовать метод setCheckable():
Если есть необходимость добавить несколько пунктов меню с флажками или переключателями, то можно объединить их в группы меню, создав отдельный идентификатор. Пункт меню добавляется в группу через метод add(), передав ему в качестве первого параметра идентификатор группы меню. Допустим, мы объявили идентификаторы для группы меню Цвет и элементов меню для установки цвета:
Теперь для создания группы меню с флажками нужно назначить идентификатор группы на каждый пункт меню и вызвать метод setGroupCheckable() для всей группы (этом случае нет необходимости вызывать метод setCheckable() для каждого пункта меню):
У метода setGroupCheckable() три параметра:
- первый параметр — идентификатор группы меню;
- второй параметр — true, если в группе разрешены переключатели или флажки;
- третий параметр — устанавливает единственный (true) или множественный (false) выбор пунктов меню. Этот параметр фактически определяет внешний вид меню — это будет меню с переключателями или флажками.
Для управления состоянием флажков и переключателей в обработчике события выбора пункта меню нужно написать следующее:
Запустите проект, вызовите меню и выберите пункт меню Цвет. У вас появится подменю с тремя пунктами (Красный, Зеленый, Синий) в виде флажков. Состояние флажков и переключателей обрабатывается в коде программы и сохраняется при повторных вызовах меню.
Можно сразу назначить намерение выбранному пункту меню через метод setIntent(), которое сработает при нажатии этого пункта, если данное событие не было перехвачено обработчиками onMenuItemClickListener (устар.) или onOptionsItemSelected. Сработав, намерение передается в метод startActivity.
Программное открытие или закрытие меню
Если вам по каким-то причинам нужно программно открыть меню (например, в демонстрационных целях), то используйте метод openOptionsMenu():
Для программного закрытия меню используйте метод closeOptionsMenu(), впрочем у меня повторный вызов метода openOptionsMenu() также закрывает меню.
Программное удаление пункта меню
Допустим, мы определили пункт меню в xml-файле:
Чтобы удалить явно лишний пункт меню из нашей программы о котах, нужно получить доступ к пункту меню через метод findItem() и сделать его невидимым. Ссылку на объект Menu нужно передать в метод onCreateOptionsMenu, чтобы программа узнала об изменении состава меню.
Но у данного решения есть недостаток, если мы повернём экран, то активность пересоздатся и удалённое меню снова появится. Как же нам избавиться от сранного пёсика?
Надо запомнить состояние пункта меню и сохранить его в объекте типа Bundle в методе onSaveInstanceState, а в методе onCreate() извлечь сохранённое состояние и передать методу onPrepareOptionsMenu, который вызывается перед показом меню на экране:
Определить наличие кнопки Menu
На старых устройствах использовалась реальная кнопка Menu. В новых версиях Android меню убрали в ActionBar и её наличие в виде отдельной кнопки стало необязательным. Но многие производители по-прежнему выпускают телефоны с кнопкой для меню. Чтобы определить, есть ли такая кнопка, в Android 14 добавили новый метод, который позволит определить наличие этой кнопки.
Разметка для меню
В современных устройствах меню является частью ActionBar. И вы можете настроить разметку меню через XML.
Допустим, вы выбрали такой вариант:
В атрибуте showAsAction не используйте значение never, иначе разметку не увидите. Сама разметка задана через атрибут actionLayout. Код для разметки:
Меню в фрагментах
Меню может быть не только частью активности, но и частью фрагмента. Принцип работы практически не отличается. У фрагмента есть соответствующий метод.
FragmentManager отвечает за вызов onCreateOptionsMenu() при получении активностью обратного вызова onCreateOptionsMenu() от системы. Вы должны явно сообщить менеджеру FragmentManager, что фрагмент должен получить вызов onCreateOptionsMenu(). Для этого вызывается метод setHasOptionsMenu():
Источник