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


102

Я починаю новий проект, який використовує 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? Це здається поганим дизайном.

Відповіді:


287

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

Вам потрібно буде призначити це ActionBarActivity, а потім здійснити виклик getSupportActionBar ().

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

Вам потрібен акторський склад. Це не поганий дизайн, це зворотна сумісність.


3
Дякую. Я сподівався, що це не буде відповіддю. Я сподівався, що можливо, що getActionBar () поверне v7 ActionBar, до якого я би звернувся, якщо мені потрібна додаткова функціональність. Тепер мої фрагменти повинні бути в курсі того, який тип діяльності вони розміщуються в.
Пол

Ні, це не так, тому що getActionBar () - API активності, який не існує у старих версіях SDK (перед сот). Ось чому нам потрібні класи підтримки, які відображають функціональність нових та вдосконалених класів та API в останніх SDK.
П’єр-Антуан Лафайєт

@ Pierre-AntoineLaFayette Чому це потрібно робити в OnAttach ()? Чи не було б краще в onActivityCreate ()?
ІгорГанапольський

Так, оскільки перший виклик getSupportActionBar () буде ініціалізувати ActionBar, шукаючи перегляди в діяльності, ймовірно, краще цей виклик зробити в onActivityCreate (). Я більше просто намагався вказати, що вам потрібно почекати, поки фрагмент не активує. Я оновлю відповідь.
П’єр-Антуан Лафайєт

2
Використовуйте AppCompatActivity замість ActionBarActivity
Aparajita Sinha

37

Хоча на це питання вже є прийнята відповідь, я мушу зазначити, що це не зовсім коректно: виклик 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;
}

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();

3

Для тих, хто використовує kotlin,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.