Toolbar - Switching from drawer to back button with only one Activity

后端 未结 6 1545
予麋鹿
予麋鹿 2020-12-23 16:34

I\'ve been searching for a while on how to change between the drawer open/close icon (going from a hamburger to the arrow) to a simple back arrow. My application at the mome

相关标签:
6条回答
  • 2020-12-23 16:57
    //This if block makes the menu back button to respond to clicks
        //The onOptionsItemSelected fun for whatever reason was not capturing back menu clicks
        if (toolbar != null) {
           /* toggle = ActionBarDrawerToggle(
                    this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
            toggle.syncState()
            drawer_layout.setDrawerListener(toggle)*/
            supportFragmentManager.addOnBackStackChangedListener(object : FragmentManager.OnBackStackChangedListener {
                override fun onBackStackChanged() {
                    if (supportFragmentManager.backStackEntryCount > 0) {
                        supportActionBar?.setDisplayHomeAsUpEnabled(true) // show back button
                        toolbar.setNavigationOnClickListener(object : View.OnClickListener {
                            override fun onClick(v: View) {
                                onBackPressed()
                            }
                        })
                    } else {
                        //show hamburger
                        supportActionBar?.setDisplayHomeAsUpEnabled(false)
                        toggle.syncState()
                        toolbar.setNavigationOnClickListener(object : View.OnClickListener {
                            override fun onClick(v: View) {
                                drawer_layout.openDrawer(GravityCompat.START)
                            }
                        })
                    }
                }
            })
    
        }
    

    You need to comment out "toggle = ActionBarDrawerToggle( this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) toggle.syncState() drawer_layout.setDrawerListener(toggle)" (4-7 lines) if you are using the auto generated Navigation layout in Android Studio, else the behavior of the back menu button will be erratic. That is what i did and it worked perfectly for me. Hope this helps someone

    0 讨论(0)
  • 2020-12-23 16:59

    Put this code into onCreate() of your Activity. Works well for me. Even using compileSdk 23 and higher.

        drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if(toolbar != null) {
            toggle = new ActionBarDrawerToggle(
                    this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
            toggle.syncState();
            drawer.setDrawerListener(toggle);
            getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
                @Override
                public void onBackStackChanged() {
                    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                        getSupportActionBar().setDisplayHomeAsUpEnabled(true); // show back button
                        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                onBackPressed();
                            }
                        });
                    } else {
                        //show hamburger
                        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                        toggle.syncState();
                        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                drawer.openDrawer(GravityCompat.START);
                            }
                        });
                    }
                }
            });
    
    0 讨论(0)
  • 2020-12-23 17:11

    I had same problem with switching between hamburger menu and back arrow inside same activity when changing fragments. Here is my working solution, hope it helps to someone.

    Listener inside your activity:

    private View.OnClickListener toolbarMenuListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //will be called only if toggle.setDrawerIndicatorEnabled(false); !
                Log.v(tag,"toggle onClick:"+v.getId()+" android.R.id.home:"+android.R.id.home);
                onBackPressed();
            }
        };
    

    Code onCreate() something like:

    ...
    ...
    setSupportActionBar(toolbar);
    toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();
    
    //set listener so you know when back on arrow is pressed
    toggle.setToolbarNavigationClickListener(toolbarMenuListener);
    ...
    ...
    

    Part you are interested in with comments (Class returned is some of mine class, can set to be void):

    /**
         * Method to set up action bar drawer.
         * @param enableBackDrawerIcon set true if want to show drawer back arrow,
         *                             false to show hamburger menu.
         * @param title shown next to drawer icon
         */
        public BaseMenusActivity drawerSetupToggle(boolean enableBackDrawerIcon, String title) {
            //NOTE: order of methods call is important!
            // If you change order order of setDrawerIndicatorEnabled and setDisplayHomeAsUpEnabled
            // method calls it won't work, weird bugs will happen (like no icon at all)
            if(enableBackDrawerIcon){
                Log.v(tag,"show drawer back icon");
                //hides hamburger menu and enables View.OnClickListener to be called
                toggle.setDrawerIndicatorEnabled(false);
                //show back arrow
                if(getSupportActionBar()!=null)
                    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    
            } else {
                Log.v(tag,"show hamburger menu");
                //hide back arrow
                if(getSupportActionBar()!=null)
                    getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                //shows hamburger menu and prevents View.OnClickListener to be called
                toggle.setDrawerIndicatorEnabled(true);
            }
    
            setTitle(title);
            return this;
        }
    

    NOTE: order of called methods is important! Would be better if could just write it in 2 lines like this but WON'T WORK (at least for me):

    toggle.setDrawerIndicatorEnabled(!enableBackDrawerIcon);
         getSupportActionBar().setDisplayHomeAsUpEnabled(enableBackDrawerIcon);
    

    If you are interested why order of method calls mess things up, look into implementation of those methods.

    0 讨论(0)
  • 2020-12-23 17:13

    The answer from @matusalem works great. I just had one bit to add to it - be careful because the drawer can also be opened by swiping in from the left side of the screen. For some, this may be desired, but for me I was disabling the drawer because it didn't make sense in any fragment but my main fragment. The swipe is easily disabled here - Navigation drawer - disable swipe

    This probably belongs in a comment to the answer, but I don't have enough reputation. My apologies.

    0 讨论(0)
  • 2020-12-23 17:17

    That's probably not what you would like to hear, but even from a conceptual point of view I would go for a new activity rather than a fragment.

    Your main activity is strictly linked to the drawer, so loading a new fragment without any access to the drawer makes no sense to me (but feel free wait for other answers if you think so). A new activity would solve both problems, since it would have no drawer and could be a child of the main one.

    Your side question looks spot on also. A "Add New" activity could nicely fit into the "full-screen dialog" visual pattern from the guidelines. See:

    http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs

    This pattern has a "save", positive button on top-right, and a X. Conceptually, the X button is to cancel/abort a process, rather than navigating up some backstack. It means you are dismissing something without letting any action happen. This fits well for what you want to do.

    From a design point of view, it's easily made by a new Activity, that can stay on top of others. Also, if the point of fragments is basically being able to represent two or more at once in tablets and bigger screen - again - I wouldn't be so happy with an old fragment on my left and an "Add New" fragment on the right.

    Rather - on tablets - I would go for a floating dialog, as suggested by the guidelines.

    http://www.google.com/design/spec/components/dialogs.html#dialogs-confirmation-dialogs

    So full-screen activity with a X button for phones, and floating dialog (with buttons at the bottom) for tablets. This, to me, is the most guidelines-coherent approach.


    I recommend reading the whole link. On the difference between <- and X,

    The X differs from an Up arrow, which is used when the view’s state is constantly being saved or when apps have draft or autosave capabilities. For example, an Up arrow is used in Settings because all changes are committed immediately.

    And also

    Touching the X in this Settings example will discard all changes. Changes will be saved only upon touching Save.

    0 讨论(0)
  • 2020-12-23 17:20

    It should work even for latest API 24.

    In your activity onCreate() do this:

    final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    final DrawerLayout drawer = (DrawerLayout) view.findViewById(R.id.drawer_layout);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    
    final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, 
        R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();
    
    final View.OnClickListener originalToolbarListener = toggle.getToolbarNavigationClickListener();
    
    getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                toggle.setDrawerIndicatorEnabled(false);
                toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        getSupportFragmentManager().popBackStack();
                    }
                });
            } else {
                toggle.setDrawerIndicatorEnabled(true);
                toggle.setToolbarNavigationClickListener(originalToolbarListener);
            }
        }
    });
    
    0 讨论(0)
提交回复
热议问题