【问题标题】:Android - Switch ActionBar Back Button to Navigation ButtonAndroid - 将 ActionBar 后退按钮切换为导航按钮
【发布时间】:2016-08-03 10:49:43
【问题描述】:

我遇到以下问题:

我知道如何设置工具栏以显示后退按钮图标而不是汉堡按钮图标。

由此:

到这里:

使用:getSupportActionBar().setDisplayHomeAsUpEnabled(true);


现在,我想做相反的动作,我想从后退按钮图标转到汉堡图标:

到这里:

我该怎么做?

更新:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setSupportActionBar(mToolbar);
    getSupportActionBar().setDisplayShowTitleEnabled(false);
}

private void enableViews(boolean enable) {
    if(enable) {
        // Enables back button icon
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    } else {
        // TODO: Enables burger icon
    }
}

【问题讨论】:

标签: android android-actionbar navigation-drawer android-toolbar back-button


【解决方案1】:

您可以通过以下方式更改操作栏按钮:

        getSupportActionBar().setHomeAsUpIndicator(R.drawable.back_button);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

【讨论】:

  • 感谢您的回答,@Martín Huergo。我希望不提供可绘制图标,除非它是原生 android 可绘制图标
【解决方案2】:

使用这个

getSupportActionBar().setDisplayShowHomeEnabled(true);

【讨论】:

    【解决方案3】:
     final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);
          toolbar.setTitle(Html.fromHtml("<font color=#ffffff>" +     getString(R.string.print_s) + "</font>"));
          toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.menu_icon));
         toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                 DetailActivity.this.finish();
            }
        });
        toolbar.inflateMenu(R.menu.fav);
        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener()     {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                  item.setIcon(R.drawable.back_icon)
                  return true;
                }
                return false;
            }
        });
    

    【讨论】:

    • 感谢您的回答,@Dinesh。你读过我的赏金说明吗?
    【解决方案4】:

    尝试将styleAppTheme 的以下代码添加到您的activity's theme/style.xml 中,这将使您的hamburger icon 变为back iconanimation

    条件如果您使用带有NavigationDrawerAppCompatActivity/ActionBarActivity 的汉堡包图标

    <style name="AppTheme" parent="Theme.AppCompat.Light">
                <item name="windowActionBar">false</item>
                <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
            </style>
    
    
    <style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
        <item name="spinBars">true</item>
        <item name="color">@android:color/white</item>
    </style>
    

    希望对你有帮助!或者你只需​​要用drawable来做。

    查看link

    【讨论】:

      【解决方案5】:

      如果我假设您在布局中使用android.support.v4.widget.DrawerLayout,那么这种方法可能适合您;我只在API 21 上进行了测试,但鉴于它主要使用支持库,它应该在更低或更高的目标上工作(著名的遗言)。

      import android.support.v7.app.ActionBarDrawerToggle
      import android.support.v4.widget.DrawerLayout
      
          ActionBarDrawerToggle mDrawerToggle;
          DrawerLayout drawerLayout;
          private boolean mToolBarNavigationListenerIsRegistered = false;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
      
              setSupportActionBar(mToolbar);
              getSupportActionBar().setDisplayShowTitleEnabled(false);
              // Get DrawerLayout ref from layout
              drawerLayout = (DrawerLayout)findViewById(R.id.drawer);
              // Initialize ActionBarDrawerToggle, which will control toggle of hamburger.
              // You set the values of R.string.open and R.string.close accordingly.
              // Also, you can implement drawer toggle listener if you want.
              mDrawerToggle = new ActionBarDrawerToggle (this, drawerLayout, mToolbar, R.string.open, R.string.close);
              // Setting the actionbarToggle to drawer layout
              drawerLayout.addDrawerListener(mDrawerToggle);
              // Calling sync state is necessary to show your hamburger icon...
              // or so I hear. Doesn't hurt including it even if you find it works
              // without it on your test device(s)
              mDrawerToggle.syncState();
          }
      
          /**
           * To be semantically or contextually correct, maybe change the name
           * and signature of this function to something like:
           *
           * private void showBackButton(boolean show)
           * Just a suggestion.
           */
           private void enableViews(boolean enable) {
      
              // To keep states of ActionBar and ActionBarDrawerToggle synchronized,
              // when you enable on one, you disable on the other.
              // And as you may notice, the order for this operation is disable first, then enable - VERY VERY IMPORTANT.
              if(enable) {
                  //You may not want to open the drawer on swipe from the left in this case  
                  drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
                  // Remove hamburger
                  mDrawerToggle.setDrawerIndicatorEnabled(false);
                  // Show back button
                  getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                  // when DrawerToggle is disabled i.e. setDrawerIndicatorEnabled(false), navigation icon
                  // clicks are disabled i.e. the UP button will not work.
                  // We need to add a listener, as in below, so DrawerToggle will forward
                  // click events to this listener.
                  if(!mToolBarNavigationListenerIsRegistered) {
                      mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
                          @Override
                          public void onClick(View v) {
                              // Doesn't have to be onBackPressed
                              onBackPressed();
                          }
                      });
      
                      mToolBarNavigationListenerIsRegistered = true;
                  }
      
              } else {
                  //You must regain the power of swipe for the drawer. 
                  drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
      
                  // Remove back button
                  getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                  // Show hamburger 
                  mDrawerToggle.setDrawerIndicatorEnabled(true);
                  // Remove the/any drawer toggle listener
                  mDrawerToggle.setToolbarNavigationClickListener(null);
                  mToolBarNavigationListenerIsRegistered = false;
              }
      
              // So, one may think "Hmm why not simplify to:
              // .....
              // getSupportActionBar().setDisplayHomeAsUpEnabled(enable);
              // mDrawer.setDrawerIndicatorEnabled(!enable);
              // ......
              // To re-iterate, the order in which you enable and disable views IS important #dontSimplify.
          }
      
      

      该解决方案使用ActionBarDrawerToggle.setDrawerIndicatorEnabled 来切换汉堡图标的可见性,并使用ActionBar.setDisplayHomeAsUpEnabled 来切换向上 按钮的可见性,本质上是利用它们各自的drawable 资源。

      其他假设

      • 您的活动主题扩展了Theme.AppCompat.Light.NoActionBar

      【讨论】:

      • 太棒了,@Ade.Akinyede!这正是我正在寻找的。你满足了我所有的赏金要求,给出了很好的解释和很好的例子,你也做了很好的分析和建议。你赢得了赏金
      • 很高兴听到它:)
      • 你拯救了我的一天!不错的解决方案!我用片段在我的应用程序中构建它,它工作正常!好工作! +1
      • @ThânHoàng 我想在你的活动中,你有抽屉布局和工具栏
      • 这个答案非常全面。谢谢楼主!
      【解决方案6】:

      我在The Google I/O 2017 Android App 中找到了灵活的解决方案。

      public Toolbar getToolbar() {
          if (mToolbar == null) {
              mToolbar = (Toolbar) findViewById(R.id.toolbar);
              if (mToolbar != null) {
                  setSupportActionBar(mToolbar);
                  mToolbar.setNavigationContentDescription(R.string.navdrawer_description_a11y);
                  mToolbarTitle = (TextView) mToolbar.findViewById(R.id.toolbar_title);
                  if (mToolbarTitle != null) {
                      int titleId = getNavigationTitleId();
                      if (titleId != 0) {
                          mToolbarTitle.setText(titleId);
                      }
                  }
      
                  // We use our own toolbar title, so hide the default one
                  getSupportActionBar().setDisplayShowTitleEnabled(false);
              }
          }
          return mToolbar;
      }
      
      /**
       * @param clickListener The {@link android.view.View.OnClickListener} for the navigation icon of
       *                      the toolbar.
       */
      protected void setToolbarAsUp(View.OnClickListener clickListener) {
          // Initialise the toolbar
          getToolbar();
          if (mToolbar != null) {
              mToolbar.setNavigationIcon(R.drawable.ic_up);
              mToolbar.setNavigationContentDescription(R.string.close_and_go_back);
              mToolbar.setNavigationOnClickListener(clickListener);
          }
      }
      

      所以用法真的很简单。

      setToolbarAsUp(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              // onBackPressed();
              // or navigate to parent or some other intent
          }
      });
      

      【讨论】:

        【解决方案7】:

        对于我来说,我想将 Burger 图标更改为 Fragment 的 ActionBar 左侧的 Back Arrow 图标,因为我正在使用 @987654324 @。还在右侧添加一个菜单

        Main Activity 中,它已经设置好了 - 默认情况下,当 Android Studio 为我创建 Navigation Drawer 时 - 像这样:

        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                        this, drawer, toolbar, R.string.navigation_drawer_open,
                        R.string.navigation_drawer_close);
        drawer.addDrawerListener(toggle);
        toggle.syncState();
        

        问题是如何自定义Fragment 中的ActionBar,所以当我转到Fragment 时,它会显示自定义的ActionBar 以及返回箭头 图标被点击,它应该离开片段并且ActionBar应该回到第一个状态。

        Fragment中(完整实现):

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setHasOptionsMenu(true); // To show the menu options
        }
        
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState){
            super.onViewCreated(view, savedInstanceState);
            showActionBar(); // the method to change ActionBar
        }
        
        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            // inflate the customized menu which already created in XML
            getActivity().getMenuInflater().inflate(R.menu.fragment_menu, menu);
            super.onCreateOptionsMenu(menu, inflater);
        }
        
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // add implementation when user select an item from the menu
            switch (item.getItemId()) {
                case R.id.option1:
                    // do something
                    return true;
                case R.id.option2:
                    // do something
                    return true;
                case R.id.option3:
                    // do something
                    return true;
                default:
                    return super.onOptionsItemSelected(item);
            }
        }
        
        private void showActionBar() {
            // get the ToolBar from Main Activity
            final Toolbar toolbar = getActivity().findViewById(R.id.toolbar);
            // get the ActionBar from Main Activity
            final ActionBar actionBar = ((AppCompatActivity)getActivity()).getSupportActionBar();
            // inflate the customized Action Bar View
            LayoutInflater inflater = (LayoutInflater) getActivity()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View v = inflater.inflate(R.layout.fragment_actionbar, null);
        
            if (actionBar != null) {
                // enable the customized view and disable title
                actionBar.setDisplayShowCustomEnabled(true);
                actionBar.setDisplayShowTitleEnabled(false);
        
                actionBar.setCustomView(v);
                // remove Burger Icon
                toolbar.setNavigationIcon(null);
        
                // add click listener to the back arrow icon
                v.findViewById(R.id.back).setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        // reverse back the show
                        actionBar.setDisplayShowCustomEnabled(false);
                        actionBar.setDisplayShowTitleEnabled(true);
                        //get the Drawer and DrawerToggle from Main Activity
                        // set them back as normal
                        DrawerLayout drawer = getActivity().findViewById(R.id.drawer_layout);
                        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                                getActivity(), drawer, toolbar, R.string.navigation_drawer_open,
                                R.string.navigation_drawer_close);
                        // All that to re-synchronize the Drawer State
                        toggle.syncState();
                        // Implement Back Arrow Icon 
                        // so it goes back to previous Fragment
                        getActivity().onBackPressed();
                    }
                });
            }
        }
        

        fragment_actionbar.xml

        <?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:layout_gravity="fill_horizontal" >
        
            <ImageView
                android:id="@+id/back"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:src="@drawable/ic_menu_back"
                android:layout_marginLeft="@dimen/_5sdp"
                android:layout_alignParentStart="true"
                android:layout_marginStart="@dimen/_5sdp" />
        
        </RelativeLayout>
        

        ic_menu_back.xml

        <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:width="24dp"
            android:height="24dp"
            android:viewportHeight="459"
            android:viewportWidth="459">
            <path
                android:fillColor="#ffffff"
                android:pathData="M178.5,140.25v-102L0,216.75l178.5,178.5V290.7c127.5,0,216.75,40.8,280.5,130.05C433.5,293.25,357,165.75,178.5,140.25z"/>
        </vector>
        

        fragment_menu.xml

        <menu xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:background="@drawable/border_shadow">
        
            <item
                android:id="@+id/option1"
                android:title="@string/show_profile"
                app:showAsAction="never"/>
            <item
                android:id="@+id/option2"
                android:title="@string/report_pic"
                app:showAsAction="never"/>
            <item
                android:id="@+id/option3"
                android:title="@string/delete_pic"
                app:showAsAction="never"/>
        </menu>
        

        【讨论】:

          【解决方案8】:

          我一直在我的应用程序上尝试其中一些示例,但它们似乎都不起作用。我正在使用片段,其中一些必须显示后退选项而不是主页。这是我的实现(在 Kotlin 中):

          override fun onResume() {
              super.onResume()
              var drawerLayout: DrawerLayout = activity.findViewById(R.id.drawer_layout)
              drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
              var actionBar = (activity as MainActivity).supportActionBar
              actionBar!!.setDisplayHomeAsUpEnabled(true)
              var  toggle= (activity as MainActivity).drawerToggle
              toggle.isDrawerIndicatorEnabled = false
              toggle.setToolbarNavigationClickListener { v ->  activity.onBackPressed() }
          }
          
          override fun onStop() {
              super.onStop()
              var drawerLayout: DrawerLayout = activity.findViewById(R.id.drawer_layout)
              drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
              var actionBar = (activity as MainActivity).supportActionBar
              actionBar!!.setDisplayHomeAsUpEnabled(false)
              var  toggle= (activity as MainActivity).drawerToggle
              toggle.setToolbarNavigationClickListener {null}
              toggle.syncState()
          }
          

          注意:这些是片段内被覆盖的 onResume 和 onStop 方法。

          备注: hamburger 图标只有在调用 toggle.syncState() 方法时才会显示。我花了将近 24 小时才弄清楚为什么没有显示主页图标。

          希望我的帖子可以帮助到别人。

          【讨论】:

          • toggle.syncState() 至关重要...谢谢您的提示!
          【解决方案9】:

          -> 如果你有一个关于 homeactivity 和 initalfragment 的抽屉,你必须显示抽屉切换,并且在内部片段之后你不想代表抽屉显示抽屉,你必须显示后退按钮并更改所有片段的标题像这样。

          • 在您的活动中公开您的 actionbartoggle。

          • 在你的主页片段中写下这段代码。

            @Override
            
            public void onResume() 
            
            {
                super.onResume();
            
                ((HomeActivity)getActivity()).getSupportActionBar().setTitle("Home");
            
                ((HomeActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
            
                ((HomeActivity)getActivity()).actionBarDrawerToggle.setDrawerIndicatorEnabled(true);}    
            
          • 并在其他片段中编写此代码:

                 @Override
                public void onResume() 
            {     super.onResume();
                    ((HomeActivity)getActivity()).getSupportActionBar().setTitle("My Account");
                    ((HomeActivity)getActivity()).actionBarDrawerToggle.setDrawerIndicatorEnabled(false);
                    ((HomeActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                }
            
          • 在你的主要活动中写上 backpressed :

            @Override
                public void onBackPressed() 
                {
                    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
            
                        getSupportFragmentManager().popBackStackImmediate();
            
                    } else {
            
                        super.onBackPressed();
            
                    }
                }
            

          【讨论】:

            【解决方案10】:

            在我看来,选择的答案太老套了。

            我尝试实现它,在这样做的同时我意识到ActionBarDrawerToggle 实际上没有什么用处(也许这就是为什么它被从有关Navigation Drawer 的官方 android 教程中删除):它不会让你当您想要在导航抽屉和操作栏之间进行协调时,生活会更轻松。

            问题是你只有 1 个主页“按钮”,它有 2 个不同的功能 - 在主屏幕中打开抽屉,然后上移 strong> 当您在应用程序中进一步下降时。将工具栏作为参数传递给ActionBarDrawerToggle 构造函数,将菜单图标添加到其中,并在单击事件时调用 openDrawer。现在如果你想切换到一个向上的事件,你必须关闭这个特殊的图标,并重新启用操作栏固有的返回功能......这仍然是一团糟。

            所以如果ActionBarDrawerToggle 对您没有帮助(但是,也许有人会想出办法),为什么要首先使用它?以下是没有它的方法:

            boolean homeShouldOpenDrawer; // flag for onOptionsItemSelected
            
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                ...
                // if you're using NoActionBar theme
                Toolbar toolbar = findViewById(R.id.toolbar);
                setSupportActionBar(toolbar);
            
                ActionBar actionbar = getSupportActionBar();
            
                // enables the home button with a <-
                actionbar.setDisplayHomeAsUpEnabled(true);
            
                // replaces the <- with the menu (hamburger) icon 
                // (ic_menu should be in every empty project, and can be easily added)
                actionbar.setHomeAsUpIndicator(R.drawable.ic_menu);
            
                // I assume your first fragment/state should be main screen, i.e. home = opens drawer
                homeShouldOpenDrawer = true;
                ...
            }
            
            private void enableViews(boolean enable) {
                if(enable) {
                    // Enables back button icon
                    // passing null or 0 brings back the <- icon
                    getSupportActionBar().setHomeAsUpIndicator(null);
                    homeShouldOpenDrawer = false;
                } else {
                    // Enables burger icon
                    getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
                    homeShouldOpenDrawer = true;
                }
            
            }
            
            // this is called whenever a selection is made from the action bar
            @Override
            public boolean onOptionsItemSelected(MenuItem item) {
                switch (item.getItemId()) {
                    case android.R.id.home:
                        if (homeShouldOpenDrawer) {
                            drawerLayout.openDrawer(GravityCompat.START);
                        } else {
                            onBackPressed();
                        }
                }
            
                return super.onOptionsItemSelected(item);
            }
            

            【讨论】:

            • 首先,删除帖子中的名称标注和否定方式。这是反社会。作为开发人员,应该清楚生态系统的变化速度有多快,解决方案也会如此。
            • 无意冒犯你。我花了 2 天时间试图协调您对本教程的回答,这就是我得出的结论。我也可能是错的,也许有更好的方法。
            • 另外,我不认为这是你的“错”,生态系统中肯定缺少动作栏和导航抽屉之间的良好连接
            【解决方案11】:

            顶级解决方案在这种情况下不起作用:

            • 一个活动和多个片段
            • 一个片段 (SettingsFragment) 应该显示后退图标而不是汉堡菜单
            • 使用 com.google.android.material.appbar.AppBarLayout、androidx.appcompat.widget.Toolbar 和 ActionBarDrawerToggle

            我在我的 Activity 的 onCreate() 中调用了这个方法:

            private fun initBackStackChangeListener() {
                supportFragmentManager.addOnBackStackChangedListener {
                    val fragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
            
                    if (fragment is SettingsFragment) {
                        menuDrawerToggle?.isDrawerIndicatorEnabled = false
                        drawer_layout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
                        menuDrawerToggle?.setToolbarNavigationClickListener { onBackPressed() }
                        supportActionBar?.setDisplayHomeAsUpEnabled(true)
                    } else {
                        supportActionBar?.setDisplayHomeAsUpEnabled(false)
                        drawer_layout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
                        menuDrawerToggle?.isDrawerIndicatorEnabled = true
                        menuDrawerToggle?.toolbarNavigationClickListener = null
                        menuDrawerToggle?.syncState()
                    }
                }
            }
            

            menuDrawerToggle 是这样的:

            menuDrawerToggle = ActionBarDrawerToggle(
                    this, drawer_layout, toolbar,
                    R.string.navigation_drawer_open,
                    R.string.navigation_drawer_close
                ).apply {
                    drawer_layout.addDrawerListener(this)
                    this.syncState()
                }
            

            像魅力一样工作。也许它可以帮助任何人。

            【讨论】:

              【解决方案12】:

              您可以使用以下来显示返回按钮而不是导航菜单。

              (activity as MainActivity).supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_arrow_back)
              

              【讨论】:

                【解决方案13】:

                我有最简单的 Kotlin 开发者解决方案

                只需将其添加到您的根活动中,片段会抵抗

                if (supportFragmentManager.backStackEntryCount > 0) {
                  supportActionBar!!.setDisplayHomeAsUpEnabled(true)
                  toolbar.setNavigationOnClickListener {
                      if (supportFragmentManager.backStackEntryCount > 0) {
                          super.onBackPressed()
                      } else {
                          supportActionBar!!.setDisplayHomeAsUpEnabled(false)
                          drawerLayout.addDrawerListener(toggle)
                          toggle.syncState()
                          drawerLayout.openDrawer(GravityCompat.START)
                      }
                  }
                } else {
                  supportActionBar!!.setDisplayHomeAsUpEnabled(false)
                  drawerLayout.addDrawerListener(toggle)
                  toggle.syncState()
                }
                

                在这里,每当 setDisplayHomeAsUpEnabled 设置为 true 时,我都会显示返回按钮。在点击它时,我会打电话给super.onBackPressed(),这与您的后退按钮的作用类似!

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-02-08
                  • 2012-04-23
                  • 2016-04-10
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-04-11
                  • 1970-01-01
                  相关资源
                  最近更新 更多