115

I'm starting a new project that uses the AppCompat/ActionBarCompat in v7 support library. I'm trying to figure out how to use the getSupportActionBar from within a fragment. My activity that hosts the fragment extends ActionBarActivity, but I don't see a similar support class for Fragments.

From within my fragment

    public class CrimeFragment extends Fragment {
          //...

          getActivity().getSupportActionBar().setSubtitle(R.string.subtitle); // getSupportActionBar is not defined in the v4 version of Fragment

          //...
    }

The google page for using it (http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html) says there should be no changes for the v4 fragment. Do I need to cast all my getActivity() calls to an ActionBarActivity? That seems like poor design.

4

7 回答 7

313

Fragment.onActivityCreated(...)之后,您将拥有一个可通过 getActivity() 访问的有效活动。

您需要将其转换为 ActionBarActivity,然后调用 getSupportActionBar()。

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

你确实需要演员表。这不是糟糕的设计,而是向后兼容。

于 2013-08-19T18:44:33.503 回答
38

虽然这个问题已经有一个公认的答案,但我必须指出它并不完全正确:调用getSupportActionBar()fromFragment.onAttach()将导致 aNullPointerException活动旋转。

简短的回答:

使用((ActionBarActivity)getActivity()).getSupportActionBar()in 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;
}
于 2014-06-10T23:21:24.483 回答
29

如果有人使用 com.android.support:appcompat-v7: 和 AppCompatActivity 作为活动,那么这将起作用

((AppCompatActivity)getActivity()).getSupportActionBar().setSubtitle(R.string.subtitle);
于 2015-08-24T11:34:55.410 回答
7

对于那些使用 kotlin 的人,

(activity as AppCompatActivity).supportActionBar.setSubtitle(R.string.subtitle)
于 2019-01-26T06:01:21.323 回答
6

作为 Pierre-Antoine LaFayette 答案的更新答案

ActionBarActivity 已弃用;AppCompatActivity改为使用

((AppCompatActivity)getActivity()).getSupportActionBar();
于 2017-04-01T13:59:44.263 回答
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;
}

希望这可以帮助

于 2016-03-26T18:51:29.517 回答
0

作为 GzDev 答案的附录,如果您已经有了字符串,则可以使用 kotlin 的自动设置器:

(activity as AppCompatActivity).supportActionBar?.subtitle = my_string

您只需使用空字符串即可将其关闭。

请注意,这适用于titlesubtitle

于 2021-05-24T15:11:52.210 回答