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

104

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

Павел
источник

Ответы:

290

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

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

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

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

Пьер-Антуан ЛаФайет
источник
3
Спасибо. Я надеялся, что это не ответ. Я надеялся, что, возможно, getActionBar () вернет ActionBar v7, который я бы использовал, если бы мне понадобились дополнительные функции. Теперь мои фрагменты должны знать, в каком типе действий они размещены.
Пол
Нет, это не так, потому что getActionBar () - это API действий, которого нет в более старых версиях SDK (до соты). Вот почему нам нужны классы поддержки, которые отражают функциональность новых и улучшенных классов и API в более поздних SDK.
Пьер-Антуан ЛаФайетт,
@ Pierre-AntoineLaFayette Почему это нужно делать в onAttach ()? Разве не лучше в onActivityCreated ()?
Игорь Ганапольский
Да, поскольку первый вызов getSupportActionBar () инициализирует ActionBar путем поиска представлений в действии, вероятно, лучше, чтобы этот вызов выполнялся в onActivityCreated (). Я больше просто пытался указать, что вам нужно подождать, пока фрагмент не будет активен. Обновлю ответ.
Pierre-Antoine LaFayette,
2
Используйте AppCompatActivity вместо ActionBarActivity
Aparajita Sinha
37

Хотя на этот вопрос уже есть принятый ответ, я должен отметить, что он не совсем правильный: вызов getSupportActionBar()from Fragment.onAttach()вызовет a, 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()is FragmentActivity.onCreate(), который восстанавливает все предыдущие фрагменты после поворота ( FragmentManagerImpl.dispatchCreate(), & c).
  • mImpl.onCreate(savedInstanceState)is 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;
}
матиаш
источник
2
ActionBarActivityустарела. Используйте AppCompatActivityвместо этого
Саман Саттари
29

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

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
Амир
источник
5

в вашем 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;
}

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

Башир АЛЬ-МОМАНИ
источник
5

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

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

((AppCompatActivity)getActivity()).getSupportActionBar();
Дассер Басюни
источник
4

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

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
GzDevs
источник