GetSupportActionBar изнутри фрагмента ActionBarCompat
Я запускаю новый проект, который использует библиотеку поддержки AppCompat/ActionBarCompat
in v7
. Я пытаюсь понять, как использовать getSupportActionBar
изнутри фрагмента. Моя активность, которая содержит фрагмент, расширяет ActionBarActivity
, но я не вижу подобного класса поддержки для фрагментов.
Из моего фрагмента
public class CrimeFragment extends Fragment {
//...
getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment
//...
}
Страница Google для ее использования (http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html) говорит, что для фрагмента v4
не должно быть никаких изменений. Нужно ли использовать все мои вызовы getActivity()
для ActionBarActivity
? Это похоже на плохой дизайн.
Ответы
Ответ 1
После Fragment.onActivityCreated(...) у вас будет действительное действие, доступное через getActivity().
Вам нужно будет привести его к ActionBarActivity, а затем сделать вызов getSupportActionBar().
((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
Вам нужен актерский состав. Это не плохой дизайн, это обратная совместимость.
Ответ 2
Пока этот вопрос уже принят, я должен указать, что это не совсем правильно: вызов getSupportActionBar()
из Fragment.onAttach()
приведет к тому, что NullPointerException
будет повернут.
Короткий ответ:
Используйте ((ActionBarActivity)getActivity()).getSupportActionBar()
в onActivityCreated()
(или любую точку после этого в своем жизненном цикле) вместо onAttach()
.
Длинный ответ:
Причина в том, что если ActionBarActivity
воссоздается после поворота, он восстанавливает все фрагменты до фактического создания объекта ActionBar
.
Исходный код для ActionBarActivity
в библиотеке support-v7
:
@Override
protected void onCreate(Bundle savedInstanceState) {
mImpl = ActionBarActivityDelegate.createDelegate(this);
super.onCreate(savedInstanceState);
mImpl.onCreate(savedInstanceState);
}
-
ActionBarActivityDelegate.createDelegate()
создает объект mImpl
в зависимости от версии Android.
-
super.onCreate()
FragmentActivity.onCreate()
, который восстанавливает любые предыдущие фрагменты после вращения (FragmentManagerImpl.dispatchCreate()
, & c).
-
mImpl.onCreate(savedInstanceState)
ActionBarActivityDelegate.onCreate()
, который читает переменную mHasActionBar
из стиля окна.
- До
mHasActionBar
true, getSupportActionBar()
всегда будет возвращать null
.
Источник ActionBarActivityDelegate.getSupportActionBar()
:
final ActionBar getSupportActionBar() {
// The Action Bar should be lazily created as mHasActionBar or mOverlayActionBar
// could change after onCreate
if (mHasActionBar || mOverlayActionBar) {
if (mActionBar == null) {
... creates the action bar ...
}
} else {
// If we're not set to have a Action Bar, null it just in case it been set
mActionBar = null;
}
return mActionBar;
}
Ответ 3
Если кто-то использует com.android.support:appcompat-v7: и AppCompatActivity как активность, то это будет работать
((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
Ответ 4
в fragment.xml
добавить тег Toolbar
из библиотеки поддержки
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
Теперь, как мы можем управлять им из класса MyFragment
? посмотрим
внутри onCreateView
функция добавляет следующие
mToolbar = (Toolbar) view.findViewById(R.id.toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(mToolbar);
//add this line if you want to provide Up Navigation but don't forget to to
//identify parent activity in manifest file
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
и если вы хотите добавить items
на панель инструментов в MyFragment
вы must
добавьте эту строку внутри функции onCreateView
setHasOptionsMenu(true);
эта строка важна, если вы ее забудете, андроид не заполнит ваши пункты меню.
предположим, что мы идентифицируем их в menu/fragment_menu.xml
после этого переопределить следующие функции
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_1:
// do stuff
return true;
case R.id.action_2:
// do more stuff
return true;
}
return false;
}
надеюсь, что это поможет
Ответ 5
Как обновленный ответ для ответа Пьера-Антуана ЛаФэйетта
ActionBarActivity устарела; используйте AppCompatActivity
вместо
((AppCompatActivity)getActivity()).getSupportActionBar();
Ответ 6
Для тех, кто использует kotlin,
(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)