Barre d'outils-passage d'un tiroir à l'autre bouton avec une seule activité

j'ai cherché pendant un certain temps sur la façon de passer entre le tiroir ouvrir/fermer l'icône (allant d'un hamburger à la flèche) à une flèche arrière simple. Mon application n'a pour l'instant qu'une seule activité qui oscille entre plusieurs fragments. À un moment, je veux faire la transition entre l'un des fragments principaux (c'est-à-dire l'un des fragments dans le tiroir) et un fragment qui est hiérarchiquement sous le fragment précédent (c'est-à-dire un fragment "ajouté"). Dans ce nouveau fragment, je veux avoir la barre d'outils pour afficher le bouton de retour au lieu du bouton de tiroir.

j'ai cherché et essayé différentes solutions pendant un certain temps. Voici les plus notables:

en ce moment, je pense à une méthode longue et ardue de créer une icône personnalisée que je cache et montre (et Cache/montre l'icône du tiroir natif). Cependant, est-il un meilleur moyen pour basculer entre le tiroir et le dos boutons?

comme un côté encore apparenté question, j'ai regardé les documents de conception de matériaux, et quelques exemples ont un X dans le coin supérieur gauche. En quoi est-ce différent de mettre en œuvre que la mise en œuvre du tiroir vs boutons back/up?

Merci~

Edit:

je peux trouver comment remplacer l'icône, mais comment obtenir l'événement de clic?

jusqu'à présent, c'était ma meilleure:

Ce que j'ai essayé aujourd'hui:

  • désactivé le tire-bouchon lorsque nécessaire (c'est-à-dire mDrawerToggle.setDrawerIndicatorEnabled(useDrawer); )
  • a ajouté les logs dans onoptionsitemsélectionné dans ma NavigationDrawerFragment, mon activité, ainsi que le DialogFragment que je suis en train de tester qui fonctionnent si item.getItemId() == android.R.id.home est vrai. Aucun de ces énoncés de journal ne s'éteint

pour un meilleur contexte, j'ai maintenant un fragment plein écran qui ajoute un bouton" Enregistrer "au menu et change l'icône de tiroir en un"X". Le fragment peut obtenir l'événement save menu, mais même L'activité et le tiroir ne peuvent pas obtenir lorsque le X est mis sur écoute.

Edit2:

comme demandé, voici un code. Notez que c'est tout de ce GitHub repo , sur lequel je travaille activement (notez que j'ai quelques fonctions inutiles ici ou il y a de tests rapides).

ActivityMain :

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

    // Add the toolbar
    mToolbar = (Toolbar) findViewById(R.id.toolbar);
    if (mToolbar != null) {
        setSupportActionBar(mToolbar);
    }

    // Initialize the drawer
    mNavigationDrawerFragment = (NavigationDrawerFragment)
            getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);

    // Set up the drawer
    mNavigationDrawerFragment.setUp(
            R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout),
            mToolbar);

    // TODO: Check if this helps to catch the main toolbar button click
    getSupportActionBar().setDisplayShowHomeEnabled(true);

    // Get the titles for the Toolbar
    mTitles = getResources().getStringArray(R.array.drawer_items);

    mDrawerPosition = -1;
    if (savedInstanceState == null) {
        // If there was no saved position, then the default, starting position should be used
        forceChangeItemSelected(0);
    }
    else {
        // Otherwise, get the saved position from the bundle
        int position = savedInstanceState.getInt(KEY_DRAWERPOS);
        mNavigationDrawerFragment.setSelectedItem(position);
        // Title needs to be re-set
        getSupportActionBar().setTitle(mTitles[position]);
    }

    // If I include the below bit, then the DrawerToggle doesn't function
        // I don't know how to switch it back and forth
    mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(LOG_TAG, "Navigation was clicked");

        }
    });
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    Log.d(LOG_TAG, "Activity responding to menu click...");
    if(item.getItemId() == android.R.id.home) Log.d(LOG_TAG, "Activity got it....");

    // If the fragment is supposed to handle things, then let it
    if(mIsFragmentHandlingMenus) return false;

    int id = item.getItemId();
    if(id == R.id.save) {
        // This isn't implemented! If chosen, then there's a bug!
        Log.e(LOG_TAG, "onOptionsItemSelected: Save was selected!");
    }

    return super.onOptionsItemSelected(item);
}

@Override
public void fragmentHandlingMenus(boolean isFragmentHandlingMenus) {
    // Simply store the setting
    mIsFragmentHandlingMenus = isFragmentHandlingMenus;

    // Toggle the drawer as necessary
    mNavigationDrawerFragment.toggleDrawerUse(!isFragmentHandlingMenus);
}

NavigationDrawerFragment :

public void toggleDrawerUse(boolean useDrawer) {
    // Enable/Disable the icon being used by the drawer
    mDrawerToggle.setDrawerIndicatorEnabled(useDrawer);

    // TODO: Enable/Disable the drawer even being able to open/close
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Log.d(LOGTAG, "Drawer responding to menu click...");
    if(item.getItemId() == android.R.id.home) Log.d(LOGTAG, "Drawer got it....");
    if (mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

GoalAdderFragment :

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    // Allow this fragment to handle toolbar menu items
    setHasOptionsMenu(true);

    // Set up the toolbar
    ((ActionBarActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    ((ActionBarActivity) getActivity()).getSupportActionBar().setHomeAsUpIndicator(android.R.drawable.ic_menu_close_clear_cancel);
    ((ActionBarActivity) getActivity()).getSupportActionBar().setTitle(getResources().getString(R.string.title_addgoal));
}

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);

    // Cache the Activity as the frag handler if necessary
    if(mFragHandler == null)
        mFragHandler = (TransactionHandler.FragmentTransactionHandler) getActivity();
    // Tell the Activity to let fragments handle the menu events
    mFragHandler.fragmentHandlingMenus(true);
}

@Override
public void onDetach() {
    super.onDetach();

    // Tell the Activity that it can now handle menu events once again
    mFragHandler.fragmentHandlingMenus(false);
}

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Log.d(LOGTAG, "Item id: " + item.getItemId() + " | Save id: " + R.id.save);
    Toast.makeText(getActivity(), "Fragment activated!", Toast.LENGTH_SHORT).show();

    switch (item.getItemId()) {
        case R.id.save:
            return true;
        case android.R.id.home:
            return true;
        default:
            break;
    }

    return false;
}

Solution:

C'est la solution ultime j'ai fini, avec l'aide de la réponse acceptée ci-dessous:

NavigationDrawerFragment :

private View.OnClickListener mOriginalListener;

public void setUp(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) {
     /* Rest of setting up code */

     // Save the default listener after setting everything else up
     mOriginalListener = mDrawerToggle.getToolbarNavigationClickListener();
}

// Tells the toolbar+drawer to switch to the up button or switch back to the normal drawer
public void toggleDrawerUse(boolean useDrawer) {
    // Enable/Disable the icon being used by the drawer
    mDrawerToggle.setDrawerIndicatorEnabled(useDrawer);

    // Switch between the listeners as necessary
    if(useDrawer)
        mDrawerToggle.setToolbarNavigationClickListener(mOriginalListener);
    else
        mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getActivity(), "Custom listener", Toast.LENGTH_SHORT).show();
            }
        });
}
36
demandé sur Community 2015-02-16 00:39:46

5 réponses

ce n'est probablement pas ce que vous voulez entendre, mais même d'un point de vue conceptuel, je pencherais pour une nouvelle activité plutôt qu'un fragment.

votre activité principale est strictement liée au tiroir, donc charger un nouveau fragment sans accès au tiroir n'a aucun sens pour moi (mais n'hésitez pas à attendre d'autres réponses si vous le pensez). Une nouvelle activité résoudrait les deux problèmes, puisqu'elle n'aurait pas de tiroir et pourrait être un enfant du principal.

votre question secondaire semble aussi à sa place. Une activité" ajouter une nouvelle "pourrait très bien s'insérer dans le" dialogue plein-écran " motif visuel des lignes directrices. Voir:

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

Ce modèle a un bouton" save", positif en haut à droite, et un X. conceptuellement, le bouton X est d'annuler/avorter un processus, plutôt que de naviguer dans le dos. Il cela signifie que vous rejetez quelque chose sans laisser aucune action se produire. Cela correspond bien à ce que vous voulez faire.

d'un point de vue design, il est facilement fait par un nouveau Activity , qui peut rester sur le dessus des autres. En outre, si le point de fragments est essentiellement être en mesure de représenter deux ou plusieurs à la fois dans les tablettes et l'écran plus grand - encore une fois - je ne serais pas aussi heureux avec un vieux fragment sur ma gauche et un "Ajouter nouveau" fragment sur la droite.

plutôt - sur les tablettes-j'irais pour un dialogue flottant, comme suggéré par les lignes directrices.

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

donc activité plein écran avec un bouton X pour les téléphones, et Dialogue flottant (avec des boutons en bas) pour les tablettes. C'est, pour moi, la plupart des lignes directrices-approche cohérente.


je recommande la lecture du tout lien. Sur la différence entre <- et X,

le X diffère d'une flèche ascendante, qui est utilisée lorsque l'état de la vue est constamment sauvegardé ou lorsque les applications ont des capacités de draft ou d'autosave. Par exemple, une flèche vers le haut est utilisée dans les paramètres parce que tous les changements sont engagés immédiatement.

et aussi

toucher le X dans cet exemple de paramètres sera jetez tous les changements. Les modifications ne seront sauvegardées qu'en touchant Save.

12
répondu natario 2015-02-15 22:29:26

mettez ce code dans onCreate() de votre Activity . Fonctionne bien pour moi. Même en utilisant compileSdk 23 et plus.

    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);
                        }
                    });
                }
            }
        });
43
répondu matusalem 2016-08-04 13:35:13

Il faut travailler encore pour les dernières API 24 .

dans votre activité onCreate() faites ceci:

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);
        }
    }
});
27
répondu mixel 2016-07-30 13:16:44

la réponse de @matusalem fonctionne très bien. J'ai juste eu un peu de ajouter - être prudent, car le tiroir peut être ouvert par un balayage à partir du côté gauche de l'écran. Pour certains, cela peut être souhaitable, mais pour moi, je désactivais le tiroir parce que cela n'avait de sens que dans mon fragment principal. Le swipe est désactivé facilement ici - tiroir de Navigation-déviation désactivable

cela appartient probablement dans un commentaire à la réponse, mais je n'ai pas assez de réputation. Toutes mes excuses.

4
répondu tpankake 2017-05-23 12:18:07

j'ai eu le même problème avec le changement entre le menu hamburger et la flèche arrière à l'intérieur de la même activité lors du changement de fragments. Voici ma solution de travail, espérons qu'il aide à quelqu'un.

L'auditeur dans votre activité:

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() quelque chose comme:

...
...
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);
...
...

partie qui vous intéresse avec commentaires (La classe retournée fait partie de la classe mine, peut être annulée):

/**
     * 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 : l'ordre des méthodes appelées est important! Serait mieux si pourrait simplement l'écrire en 2 lignes comme ceci mais ne fonctionnera pas (au moins pour moi):

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

si vous êtes intéressé pourquoi l'ordre des appels de méthode gâche les choses, regardez dans la mise en œuvre de ces méthodes.

0
répondu user1540907 2017-04-28 10:54:58