Android - 将 ActionBar 后退按钮切换为导航按钮

Posted

技术标签:

【中文标题】Android - 将 ActionBar 后退按钮切换为导航按钮【英文标题】:Android - Switch ActionBar Back Button to Navigation Button 【发布时间】: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
    

【问题讨论】:

也许这个链接会帮助你***.com/a/28072236/1607191 【参考方案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_
    android:layout_
    android:layout_gravity="fill_horizontal" >

    <ImageView
        android:id="@+id/back"
        android:layout_
        android:layout_
        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:
    android:
    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(),这与您的后退按钮的作用类似!

【讨论】:

以上是关于Android - 将 ActionBar 后退按钮切换为导航按钮的主要内容,如果未能解决你的问题,请参考以下文章

当用户按下后退按钮时隐藏导航抽屉

如何实现Android ActionBar 后退按钮?

Android Studio:如何从 Fragment 在 ActionBar 中实现后退按钮

ActionBar Android Appcelerator中的后退按钮[复制]

ActionBar的后退主页按钮无法使用片段

ActionBar在发布版本中缺少后退箭头,但没有调试版本