В этом уроке:
- программно размещаем элементы в ActionBar
- используем элементы из фрагментов
Недавно на форуме был вопрос о том, как во время работы программы менять содержимое ActionBar. Тема действительно интересная, и незаслуженно мною пропущенная. В этом уроке будем с ней разбираться.
Опробуем три способа работы с элементами:
1) Добавление/удаление MenuItem в объект Menu
2) Показ/скрытие группы в Menu
3) Элементы, относящиеся к фрагментам
С первыми двумя пунктами все понятно, эти механизмы мы рассматривали еще в Уроке 14.
Более интересен третий пункт. Фрагмент может реализовать в себе метод onCreateOptionsMenu и, тем самым, создать свои элементы для ActionBar. Как только фрагмент будет добавлен на экран, эти элементы добавятся в ActionBar. А когда фрагмент с экрана уберут, элементы исчезнут.
Создадим приложение, которое реализует три этих варианта.
Создадим проект:
Project name: P1121_DynamicActionBar
Build Target: Android 4.1
Application name: DynamicActionBar
Package name: ru.startandroid.develop.p1121dynamicactionbar
Create Activity: MainActivity
Добавим строки в strings.xml:
<string name="add_del">Добавить/удалить</string> <string name="visible">Показать/скрыть</string> <string name="fragment">Фрагмент</string> <string name="frag1_text">Fragment 1</string> <string name="frag2_text">Fragment 2</string> <string name="menu_item1">Item 1</string> <string name="menu_item2">Item 2</string> <string name="menu_item31">Item 31</string> <string name="menu_item32">Item 32</string>
Создадим два фрагмента. Начнем с layout-файлов.
fragment1.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#77ff0000" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/frag1_text"> </TextView> </LinearLayout>
fragment2.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#7700ff00" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/frag2_text"> </TextView> </LinearLayout>
Файлы с пунктами меню (они же - элементы ActionBar):
res/menu/fragment1.xml:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/frag1_item" android:icon="@android:drawable/ic_dialog_info" android:showAsAction="ifRoom|withText" android:title="@string/menu_item31"> </item> </menu>
res/menu/fragment2.xml:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/frag2_item" android:icon="@android:drawable/ic_dialog_email" android:showAsAction="ifRoom|withText" android:title="@string/menu_item32"> </item> </menu>
По одному элементу для каждого фрагмента. Эти элементы будут появляться в ActionBar при выводе фрагмента на экран.
Классы.
Fragment1.java:
package ru.startandroid.develop.p1121dynamicactionbar; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; public class Fragment1 extends Fragment { public void onCreate(Bundle savedInstanceState) { setHasOptionsMenu(true); super.onCreate(savedInstanceState); } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment1, null); } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.fragment1, menu); super.onCreateOptionsMenu(menu, inflater); } }
Fragment2.java:
package ru.startandroid.develop.p1121dynamicactionbar; import android.app.Fragment; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; public class Fragment2 extends Fragment { public void onCreate(Bundle savedInstanceState) { setHasOptionsMenu(true); super.onCreate(savedInstanceState); } public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment2, null); } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.fragment2, menu); super.onCreateOptionsMenu(menu, inflater); } }
В onCreate с помощью setHasOptionsMenu включаем режим вывода элементов фрагмента в ActionBar.
В onCreateView создаем View, в onCreateOptionsMenu – меню. Все как обычно.
Фрагменты готовы.
Теперь займемся Activity. Перепишем res/layout/main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <CheckBox android:id="@+id/chbAddDel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="@string/add_del"> </CheckBox> <CheckBox android:id="@+id/chbVisible" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="@string/visible"> </CheckBox> <Button android:id="@+id/btnFrag" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onClick" android:text="@string/fragment"> </Button> <FrameLayout android:id="@+id/cont" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> </LinearLayout>
Два чекбокса и кнопка. Чекбоксы отвечают за работу с элементами с помощью первого и второго способов. Кнопка будет показывать поочередно два фрагмента в контейнере cont.
res/menu/main.xml:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:id="@+id/groupVsbl"> <item android:id="@+id/item2" android:icon="@android:drawable/ic_menu_call" android:showAsAction="always|withText" android:title="@string/menu_item2"> </item> </group> </menu>
Создаем группу, а в ней элемент. Эту группу будем скрывать и показывать.
MainActivity.java:
package ru.startandroid.develop.p1121dynamicactionbar; import android.app.Activity; import android.app.Fragment; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.CheckBox; public class MainActivity extends Activity { final int MENU_ID = 1; CheckBox chbAddDel; CheckBox chbVisible; Fragment frag1; Fragment frag2; Fragment frag; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); chbAddDel = (CheckBox) findViewById(R.id.chbAddDel); chbVisible = (CheckBox) findViewById(R.id.chbVisible); frag = frag1 = new Fragment1(); frag2 = new Fragment2(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); menu.setGroupVisible(R.id.groupVsbl, chbVisible.isChecked()); if (chbAddDel.isChecked()) { menu.add(0, MENU_ID, 0, R.string.menu_item1) .setIcon(android.R.drawable.ic_delete) .setShowAsAction( MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT); } else { menu.removeItem(MENU_ID); } return true; } public void onClick(View view) { switch (view.getId()) { case R.id.chbAddDel: case R.id.chbVisible: invalidateOptionsMenu(); break; case R.id.btnFrag: frag = (frag == frag1) ? frag2 : frag1; getFragmentManager().beginTransaction().replace(R.id.cont, frag) .commit(); break; default: break; } } }
В onCreateOptionsMenu настраиваем видимость группы groupVsbl в зависимости от значения чекбокса chbVisible.
В зависимости от значения чекбокса chbAddDel создаем или удаляем элемент.
В onСlick для чекбоксов вызываем метод invalidateOptionsMenu - перерисовка меню/ActionBar. А по нажатию на кнопку поочередно выводим на экран Fragment1 или Fragment2.
Все сохраняем и запускаем приложение.
Жмем галку Добавить/удалить. Появляется элемент. Мы добавили MenuItem в Menu.
Жмем галку Показать/скрыть. Появляется элемент. Мы показали группу меню, в которой один пункт.
Соответственно, убирая галки - убираете элементы.
Понажимаем кнопку Фрагмент. Появляется элемент то одного, то другого фрагмента.
Еще, как вариант, можно играться с видимостью не всей группы, а конкретного элемента - метод setVisible.
Если в ActionBar нажать на overflow-кнопку, будет вызван метод onPrepareOptionsMenu для Activity и для фрагмента, который сейчас отображен.
На следующем уроке:
- работаем с ActionMode
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня