来自片段 ActionBarCompat 内部的 getSupportActionBar

我正在启动一个使用 v7支持库中的 AppCompat/ActionBarCompat的新项目。我正试图从一个片段中找出如何使用 getSupportActionBar。承载片段的活动扩展了 ActionBarActivity,但是我没有看到类似的片段支持类。

从我的碎片里

    public class CrimeFragment extends Fragment {
//...


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


//...
}

谷歌页面使用它(http://android-developers.blogspot.in/2013/08/actionbarcompat-and-io-2013-app-source.html)说,应该没有改变的 v4片段。我需要将所有的 getActivity()调用转换为 ActionBarActivity调用吗?这设计好像不怎么样。

104021 次浏览

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

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

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

你确实需要演员阵容,不是设计不好,而是向后兼容。

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

简短的回答:

onActivityCreated()中使用 ((ActionBarActivity)getActivity()).getSupportActionBar()(或其生命周期中的任何一点)而不是 onAttach()

长话短说:

原因是如果在一次旋转之后重新创建一个 ActionBarActivity,它将恢复实际创建 ActionBar对象的所有片段 之前

support-v7库中 ActionBarActivity的源代码:

@Override
protected void onCreate(Bundle savedInstanceState) {
mImpl = ActionBarActivityDelegate.createDelegate(this);
super.onCreate(savedInstanceState);
mImpl.onCreate(savedInstanceState);
}
  • ActionBarActivityDelegate.createDelegate() creates the mImpl object depending on the Android version.
  • super.onCreate()FragmentActivity.onCreate(),它在一次旋转(FragmentManagerImpl.dispatchCreate(),& c)之后恢复以前的任何片段。
  • mImpl.onCreate(savedInstanceState) is ActionBarActivityDelegate.onCreate(), which reads the mHasActionBar variable from the window style.
  • Before mHasActionBar is true, getSupportActionBar() will always return null.

资料来源:

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;
}

If someone uses com.android.support:appcompat-v7: and AppCompatActivity as activity then this will work

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

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" />

Now how we can control it from MyFragment class? let's see

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中的工具栏 you must add this line inside onCreateView function

        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;
}

hope this helps

作为对 Pierre-Antoine LaFayette 答案的最新回答

不推荐使用 ActionBarActivity; 而是使用 AppCompatActivity

((AppCompatActivity)getActivity()).getSupportActionBar();

对于那些使用 kotlin 的人,

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

作为 GzDev 答案的补充,如果你已经有了字符串,你可以使用 kotlin 的自动调整器:

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

您可以通过使用一个空字符串来关闭它。

注意,这对 书名字幕都适用。