Impossibile catturare l'evento clic sul pulsante home della barra degli strumenti


106

Ho implementato la più recente libreria appcompat e utilizzando il Toolbar barra delle azioni as. Ma il problema è che non riesco a rilevare l'evento clic sul pulsante home / icona dell'hamburger. Ho provato e guardato tutto ma non sembra trovare un problema simile.

Questa è la mia Activityclasse:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    // Set up the drawer.
    navDrawerFragment = 
        (NavigationDrawerFragment) getSupportFragmentManager()
        .findFragmentById(R.id.navigation_drawer);
    navDrawerFragment.setUp(
        R.id.navigation_drawer, 
        (DrawerLayout) findViewById(R.id.drawer_layout), 
        toolbar);
}

E questa è la mia classe NavigationDrawerFragment:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (savedInstanceState != null) {
        currentSelectedPosition = savedInstanceState.getInt(
            STATE_SELECTED_POSITION);
        fromSavedInstanceState = true;
    }

    // Select either the default item (0) or the last selected item.
    selectItem(currentSelectedPosition);
}

@Override
public void onActivityCreated (Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    // Indicate that this fragment would like 
    // to influence the set of actions in the action bar.
    setHasOptionsMenu(true);
}

public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        drawerListView = (ListView) inflater.inflate(
            R.layout.fragment_navigation_drawer, container, false);
        drawerListView.setOnItemClickListener(
            new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, 
                View view, int position, long id) {
                selectItem(position);
            }
        });
        //mDrawerListView.setAdapter();
        //mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
        return drawerListView;
}

public void setUp(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) {
    fragmentContainerView = getActivity().findViewById(fragmentId);
    this.drawerLayout = drawerLayout;

    // set a custom shadow that overlays the main 
    // content when the drawer opens
    drawerLayout.setDrawerShadow(
        R.drawable.drawer_shadow, GravityCompat.START);
    // set up the drawer's list view 
    // with items and click listener

    ActionBar actionBar = getActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setHomeButtonEnabled(true);

    // ActionBarDrawerToggle ties together the the proper interactions
    // between the navigation drawer and the action bar app icon.
    drawerToggle = new ActionBarDrawerToggle(
        getActivity(), 
        drawerLayout, 
        toolbar, 
        R.string.navigation_drawer_open, 
        R.string.navigation_drawer_close) {
        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);
        }

        public void onDrawerOpened(View drawerView) {
            super.onDrawerOpened(drawerView);
        }
    };

    // If the user hasn't 'learned' about the drawer, 
    // open it to introduce them to the drawer,
    // per the navigation drawer design guidelines.
    if (!userLearnedDrawer && !fromSavedInstanceState) {
        drawerLayout.openDrawer(fragmentContainerView);
    }

    // Defer code dependent on restoration of previous instance state.
    drawerLayout.post(new Runnable() {
        @Override
        public void run() {
            drawerToggle.syncState();
        }
    });

    drawerLayout.setDrawerListener(drawerToggle);
}

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(STATE_SELECTED_POSITION, currentSelectedPosition);
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    // Forward the new configuration the drawer toggle component.
    drawerToggle.onConfigurationChanged(newConfig);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Log.d("cek", "item selected");
    if (drawerToggle.onOptionsItemSelected(item)) {
        Log.d("cek", "home selected");
        return true;
    }

    return super.onOptionsItemSelected(item);
}

quando si fa clic su una voce di menu, viene chiamato il registro "elemento selezionato". Ma quando clicco sul pulsante home, si apre il cassetto di navigazione ma il registro "home selected" non viene mai chiamato. Ho impostato anche il onOptionsItemSelectedmetodo nel mio Activity, ma non viene ancora chiamato.

Risposte:


224

Se vuoi sapere quando si fa clic su home, AppCompatActivitydovresti provarlo in questo modo:

Per prima cosa dì ad Android che vuoi usare il tuo Toolbarcome ActionBar:

setSupportActionBar(toolbar);

Quindi imposta Home per essere visualizzato in setDisplayShowHomeEnabledquesto modo:

getSupportActionBar().setDisplayShowHomeEnabled(true);

Infine ascolta gli eventi di clic su android.R.id.homecome al solito:

@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
    if (menuItem.getItemId() == android.R.id.home) {
        Timber.d("Home pressed");
    }
    return super.onOptionsItemSelected(menuItem);
}

Se vuoi sapere quando viene cliccato il pulsante di navigazione su un Toolbarin una classe diversa da quella AppCompatActivity, puoi utilizzare questi metodi per impostare un'icona di navigazione e ascoltare gli eventi di clic su di essa. L'icona di navigazione apparirà sul lato sinistro di Toolbardove si trovava il pulsante "home".

toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_nav_back));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("cek", "home selected");
    }
});

Se vuoi sapere quando viene cliccato l'hamburger e quando il cassetto si apre, stai già ascoltando questi eventi tramite onDrawerOpenede onDrawerClosedquindi vorrai vedere se quei callback soddisfano le tue esigenze.


1
Ho già provato la prima parte, ma non funziona. Ho provato la seconda parte e funziona. Ma l'icona non cambia se registro la barra degli strumenti con il cassetto di navigazione. Un'altra domanda, c'è qualche sostituto per setDrawerIndicatorEnabled per questo? Ho provato con questo nuovo cassetto di navigazione e ho riscontrato un errore. Grazie
Dark Leonhart

La seconda soluzione sta funzionando. Ma come possiamo rilevare il pulsante home cliccato e il pulsante del cassetto nella seconda soluzione. Quando faccio clic sull'icona del cassetto, non si apre il cassetto.
Dory

2
Quando impostiNavigationOnClickListener per la barra degli strumenti, perdi il comportamento del drawer "nativo" :(
IlyaEremin

7
Quindi ora abbiamo bisogno di un listener di clic separato quando prima in frammenti potevamo controllare android.R.id.home in onOptionsItemSelected ()? È davvero molto fastidioso
Daniel Wilson

1
re: Toolbar, se si imposta un nuovo NavigationOnClickListener (utilizzando setNavigationOnClickListener) è possibile ripristinare il NavDrawer in un secondo momento, se necessario, chiamando di nuovo setDrawerListener con ActionBarDrawerToggle.
straya

24
    mActionBarDrawerToggle = mNavigationDrawerFragment.getActionBarDrawerToggle();
    mActionBarDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // event when click home button
        }
    });

nel mio caso questo codice funziona perfettamente


Sei davvero fantastico, ha funzionato, non avrei mai pensato di poter gestire il pulsante Indietro della barra degli strumenti tramite DrawerToggle ..
Sai

Per far funzionare ActionBarDrawerToggle.setToolbarNavigationClickListener, è necessario prima chiamare questo: mActionBarDrawerToggle.setHomeAsUpIndicator (R.drawable.menu_icon); mActionBarDrawerToggle.setDrawerIndicatorEnabled (false); e gestire personalmente gli eventi dei clic. (apri / chiudi il cassetto al clic)
luky

10

Questo è il modo in cui lo faccio per tornare al frammento giusto, altrimenti se hai più frammenti sullo stesso livello tornerebbe al primo se non sovrascrivi il comportamento del pulsante Indietro della barra degli strumenti.

toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            finish();
        }
    });

Abbiamo il metodo di clic "Sostituisci" in Kotlin?
Akhila Madari

@AkhilaMadari prova qualcosa di simile in Kotlin: val toolbar = findViewById (R.id.toolbar) as Toolbar setSupportActionBar (toolbar) toolbar.setNavigationOnClickListener {/ * fai qualcosa che vuoi * / finish ()}
Marcos

3

Penso che la soluzione corretta con la libreria di supporto 21 sia la seguente

// action_bar is def resource of appcompat; 
// if you have not provided your own toolbar I mean  
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (toolbar != null) {
    // change home icon if you wish
    toolbar.setLogo(this.getResValues().homeIconDrawable());
    toolbar.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //catch here title and home icon click                          
        }                       
    });                 
}

in this.getResValues().homeIconDrawable(), chi è this?
LuisComS

Questa è un'attività. Getresvalues ​​è il mio metodo, quindi non è rilevante qui. Setlogo accetta un ID risorsa disegnabile.
Čikić Nenad

4
questo gestirà il clic dell'utente in qualsiasi punto dell'intera barra degli strumenti, non penso che questo sia quello che stava chiedendo
Mina Fawzy

1

Ho gestito il pulsante Indietro e Home nel riquadro di navigazione come

public class HomeActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {
    private ActionBarDrawerToggle drawerToggle;
    private DrawerLayout drawerLayout;
    NavigationView navigationView;
    private Context context;

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

        setContentView(R.layout.activity_home);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        resetActionBar();

        navigationView = (NavigationView) findViewById(R.id.navigation_view);
        navigationView.setNavigationItemSelectedListener(this);

        //showing first fragment on Start
        getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_fragment, new FirstFragment()).commit();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        //listener for home
        if(id==android.R.id.home)
        {  
            if (getSupportFragmentManager().getBackStackEntryCount() > 0)
                onBackPressed();
            else
                drawerLayout.openDrawer(navigationView);
            return  true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
       if (drawerLayout.isDrawerOpen(GravityCompat.START)) 
            drawerLayout.closeDrawer(GravityCompat.START);
       else 
            super.onBackPressed();
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Begin the transaction

        Fragment fragment = null;
        // Handle navigation view item clicks here.
        int id = item.getItemId();
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (id == R.id.nav_companies_list) {
            fragment = new FirstFragment();
            // Handle the action
        } 


        // Begin the transaction
        if(fragment!=null){

            if(item.isChecked()){
                if(getSupportFragmentManager().getBackStackEntryCount()==0){
                    drawer.closeDrawers();
            }else{
                    removeAllFragments();
                    getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).replace(R.id.WikiCompany, fragment).commit();
                    drawer.closeDrawer(GravityCompat.START);
                }

            }else{
                removeAllFragments();
                getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).replace(R.id.WikiCompany, fragment).commit();
                drawer.closeDrawer(GravityCompat.START);
            }
        }

        return true;
    }

    public void removeAllFragments(){
        getSupportFragmentManager().popBackStackImmediate(null,
                FragmentManager.POP_BACK_STACK_INCLUSIVE);
    }

    public void replaceFragment(final Fragment fragment) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                .replace(R.id.WikiCompany, fragment).addToBackStack("")
                .commit();
    }


    public void updateDrawerIcon() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.i("", "BackStackCount: " + getSupportFragmentManager().getBackStackEntryCount());
                    if (getSupportFragmentManager().getBackStackEntryCount() > 0)
                        drawerToggle.setDrawerIndicatorEnabled(false);
                    else
                        drawerToggle.setDrawerIndicatorEnabled(true);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }, 50);
    }

    public void resetActionBar()
    {
        //display home
        getSupportActionBar().setDisplayShowHomeEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
    }

    public void setActionBarTitle(String title) {
        getSupportActionBar().setTitle(title);
    }
}

e in ogni onViewCreatedchiamo

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    ((HomeActivity)getActivity()).updateDrawerIcon();
    ((HomeActivity) getActivity()).setActionBarTitle("List");
}

0

È così che ho implementato il design pre-materiale e sembra che funzioni ancora ora che sono passato al nuovo Toolbar. Nel mio caso, voglio accedere all'utente se tenta di aprire il nav laterale mentre è disconnesso (e catturare l'evento in modo che il nav laterale non si apra). Nel tuo caso non potresti return true;.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!isLoggedIn() && item.getItemId() == android.R.id.home) {
        login();
        return true;
    }
    return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}

Ah, dimenticavo di aver scoperto che non ero in grado di catturare il clic del pulsante home in un frammento, ho posto una domanda qui e ho suggerito una soluzione alternativa che consisteva nel trasferire manualmente l'evento su tutti i tuoi frammenti. stackoverflow.com/q/21938419/1007151
darnmason

0

Ho cambiato un po 'il DrawerLayout per ottenere gli eventi ed essere in grado di consumare e l'evento, ad esempio se vuoi usare l'azioneToggle come indietro se sei nella visualizzazione dei dettagli:

public class ListenableDrawerLayout extends DrawerLayout {

    private OnToggleButtonClickedListener mOnToggleButtonClickedListener;
    private boolean mManualCall;

    public ListenableDrawerLayout(Context context) {
        super(context);
    }

    public ListenableDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ListenableDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Sets the listener for the toggle button
     *
     * @param mOnToggleButtonClickedListener
     */
    public void setOnToggleButtonClickedListener(OnToggleButtonClickedListener mOnToggleButtonClickedListener) {
        this.mOnToggleButtonClickedListener = mOnToggleButtonClickedListener;
    }

    /**
     * Opens the navigation drawer manually from code<br>
     * <b>NOTE: </b>Use this function instead of the normal openDrawer method
     *
     * @param drawerView
     */
    public void openDrawerManual(View drawerView) {
        mManualCall = true;
        openDrawer(drawerView);
    }

    /**
     * Closes the navigation drawer manually from code<br>
     * <b>NOTE: </b>Use this function instead of the normal closeDrawer method
     *
     * @param drawerView
     */
    public void closeDrawerManual(View drawerView) {
        mManualCall = true;
        closeDrawer(drawerView);
    }


    @Override
    public void openDrawer(View drawerView) {

        // Check for listener and for not manual open
        if (!mManualCall && mOnToggleButtonClickedListener != null) {

            // Notify the listener and behave on its reaction
            if (mOnToggleButtonClickedListener.toggleOpenDrawer()) {
                return;
            }

        }
        // Manual call done
        mManualCall = false;

        // Let the drawer layout to its stuff
        super.openDrawer(drawerView);
    }

    @Override
    public void closeDrawer(View drawerView) {

        // Check for listener and for not manual close
        if (!mManualCall && mOnToggleButtonClickedListener != null) {

            // Notify the listener and behave on its reaction
            if (mOnToggleButtonClickedListener.toggleCloseDrawer()) {
                return;
            }

        }
        // Manual call done
        mManualCall = false;

        // Let the drawer layout to its stuff
        super.closeDrawer(drawerView);
    }

    /**
     * Interface for toggle button callbacks
     */
    public static interface OnToggleButtonClickedListener {

        /**
         * The ActionBarDrawerToggle has been pressed in order to open the drawer
         *
         * @return true if we want to consume the event, false if we want the normal behaviour
         */
        public boolean toggleOpenDrawer();

        /**
         * The ActionBarDrawerToggle has been pressed in order to close the drawer
         *
         * @return true if we want to consume the event, false if we want the normal behaviour
         */
        public boolean toggleCloseDrawer();
    }

}

0

L'approccio più semplice che potremmo fare è cambiare l'icona home in un'icona nota e confrontare i drawables (perché l'icona android.R.id.home può differire a seconda delle versioni API

quindi imposta una barra degli strumenti come barra delle azioni SetSupportActionBar (_toolbar);

_toolbar.NavigationIcon = your_known_drawable_here;

   for (int i = 0; i < _toolbar.ChildCount; i++)
            {
                View v = _toolbar.GetChildAt(i);
                if (v is ImageButton)
                {
                    ImageButton imageButton = v as ImageButton;

                    if (imageButton.Drawable.GetConstantState().Equals(_bookMarkIcon.GetConstantState()))
                    {
                       //here v is the widget that contains the home  icon you can add your click events here 
                    }
                }
            }

0

Nel mio caso ho dovuto mettere l'icona usando:

toolbar.setNavigationIcon(R.drawable.ic_my_home);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);

Quindi ascolta gli eventi di clic con l'ID predefinito onOptionsItemSelected e android.R.id.home


1
Questo non funzionerà. android.R.id.homemai sparare
Trancer

0

Per chiunque cerchi un'implementazione Xamarin (poiché gli eventi vengono eseguiti in modo diverso in C #), ho semplicemente creato questa NavClickHandlerclasse come segue:

public class NavClickHandler : Java.Lang.Object, View.IOnClickListener
{
    private Activity mActivity;
    public NavClickHandler(Activity activity)
    {
        this.mActivity = activity;
    }
    public void OnClick(View v)
    {
        DrawerLayout drawer = (DrawerLayout)mActivity.FindViewById(Resource.Id.drawer_layout);
        if (drawer.IsDrawerOpen(GravityCompat.Start))
        {
            drawer.CloseDrawer(GravityCompat.Start);
        }
        else
        {
            drawer.OpenDrawer(GravityCompat.Start);
        }
    }
}

Quindi, assegnato un pulsante del menu hamburger personalizzato come questo:

        SupportActionBar.SetDisplayHomeAsUpEnabled(true);
        SupportActionBar.SetDefaultDisplayHomeAsUpEnabled(false);
        this.drawerToggle.DrawerIndicatorEnabled = false;
        this.drawerToggle.SetHomeAsUpIndicator(Resource.Drawable.MenuButton);

E infine, assegnato al commutatore del menu del cassetto un ToolbarNavigationClickListener del tipo di classe che ho creato in precedenza:

        this.drawerToggle.ToolbarNavigationClickListener = new NavClickHandler(this);

E poi hai un pulsante di menu personalizzato, con gli eventi di clic gestiti.


0

Prova questo codice

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if(id == android.R.id.home){
        //You can get 
    }
    return super.onOptionsItemSelected(item);
}

Aggiungi sotto il codice al tuo metodo onCreate ()

ActionBar ab = getSupportActionBar();
    ab.setDisplayHomeAsUpEnabled(true);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.