it-swarm.com.ru

getSupportActionBar изнутри фрагмента ActionBarCompat

Я начинаю новый проект, который использует библиотеку поддержки AppCompat/ActionBarCompat в 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? Это похоже на плохой дизайн.

92
Paul

После Fragment.onActivityCreated (...) у вас будет действительное действие, доступное через getActivity (). 

Вам нужно будет привести его к ActionBarActivity, а затем сделать вызов getSupportActionBar ().

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);

Вам нужен актерский состав. Это не плохой дизайн, это обратная совместимость.

259
Pierre-Antoine LaFayette

Хотя на этот вопрос уже есть принятый ответ, я должен отметить, что он не совсем корректен: вызов 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 станет истиной, 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's been set
        mActionBar = null;
    }
    return mActionBar;
}
35
matiash

Если кто-то использует com.Android.support:appcompat-v7: и AppCompatActivity в качестве действия, то это будет работать

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
29
Amir

в свой 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);

эта строка важна, если вы ее забудете, Android не будет заполнять ваши пункты меню. 

предположим, что мы идентифицируем их в 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;
}

надеюсь это поможет

4
Basheer AL-MOMANI

Как обновленный ответ на ответ Пьера-Антуана ЛаФайета

ActionBarActivity устарела; используйте вместо этого AppCompatActivity

((AppCompatActivity)getActivity()).getSupportActionBar();
3
Dasser Basyouni

Для тех, кто использует kotlin,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
0
GzDevs