【问题标题】:getSupportActionBar from inside of Fragment ActionBarCompat从 Fragment ActionBarCompat 内部 getSupportActionBar
【发布时间】:2013-08-21 15:47:24
【问题描述】:

我正在开始一个新项目,该项目使用 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?这似乎是糟糕的设计。

【问题讨论】:

    标签: android android-fragments android-support-library android-actionbar-compat


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 谢谢。我希望这不是答案。我希望 getActionBar() 可能会返回一个 v7 ActionBar,如果我需要额外的功能,我会使用它。现在我的 Fragments 必须知道它们托管在什么类型的 Activity 中。
    • 不,因为 getActionBar() 是一个 Activity API,在旧版本的 SDK(蜂窝前)上不存在。这就是为什么我们需要支持类来反映最新 SDK 中新的和改进的类和 API 的功能。
    • @Pierre-AntoineLaFayette 为什么必须在 onAttach() 中完成? onActivityCreated() 不是更好吗?
    • 是的,因为第一次调用 getSupportActionBar() 将通过在 Activity 中查找视图来初始化 ActionBar,最好在 onActivityCreated() 中完成此调用。我只是想表明您需要等到片段有活动。我会更新答案。
    • 使用 AppCompatActivity 代替 ActionBarActivity
    【解决方案2】:

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

    简答:

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

    长答案:

    原因是,如果 ActionBarActivity 在旋转后重新创建,它会在实际创建 ActionBar 对象之前恢复所有 Fragments

    ActionBarActivity 的源代码在support-v7 库中:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        mImpl = ActionBarActivityDelegate.createDelegate(this);
        super.onCreate(savedInstanceState);
        mImpl.onCreate(savedInstanceState);
    }
    
    • ActionBarActivityDelegate.createDelegate() 根据 Android 版本创建 mImpl 对象。
    • 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;
    }
    

    【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      对于那些使用 kotlin 的人,

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

      【讨论】:

        【解决方案5】:

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

        ActionBarActivity 已弃用;改用AppCompatActivity

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

        【讨论】:

          【解决方案6】:

          在您的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 内的工具栏中 你mustonCreateView 函数中添加这一行

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

          希望对你有帮助

          【讨论】:

            【解决方案7】:

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

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

            你可以通过简单地使用一个空字符串来关闭它。

            请注意,这适用于 titlesubtitle

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-05-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多