46 votes

Le clic sur l'élément de DrawerLayout - Quel est le bon moment pour remplacer fragment?

Je suis du développement d'une application qui utilise le tiroir de navigation modèle (Avec DrawerLayout).

Chaque clic sur un tiroir de l'élément, remplace le fragment dans le conteneur principal.

Cependant, je ne suis pas sûr de quand est le bon moment pour faire le fragment de la transaction? Lorsque le tiroir commence à se fermer? Ou après qu'il est fermé?

Dans google documentaion exemple, vous pouvez voir qu'ils sont en train de faire la transaction juste après l'élément, cliquez sur, puis fermez le tiroir.
En conséquence, le dessinateur semble lag et qui n'est pas lisse, et il a l'air très mauvais (Il arrive dans ma demande trop).

Dans Gmail et Google Drive applications, dans l'autre sens, On dirait qu'ils sont en train de faire la transaction, après le tiroir fermé (Suis-je le Droit?).
En conséquence, le tiroir n'est pas de lag et très lisse, MAIS il faut environ 1 seconde (le temps qu'il faut pour le tiroir fermé) au moins, pour voir le fragment suivant.

Il semble qu'il n'y a pas de chemin le tiroir sera lisse immédiatement faire fragment de la transaction.

Que pensez-vous de cela?

Merci à l'avance!

25voto

Evelio Tarazona Points 4100

Yup, ne pouvais pas être plus d'accord, la réalisation d'un fragment (avec vue) opération entraîne une passe de mise en page qui provoque janky des animations sur les points de vues animées, citant DrawerLayout docs:

DrawerLayout.DrawerListener peut être utilisé pour surveiller l'état et le mouvement de tiroir points de vue. Éviter d'effectuer des opérations coûteuses telles que la mise en page lors de l'animation, car il peut causer bégaiement; essayez d'effectuer des opérations coûteuses au cours de la STATE_IDLE état.

Donc, merci d'effectuer votre fragment de transactions après le tiroir est fermé ou quelqu'un de patchs, la bibliothèque de prise en charge en quelque sorte de les corriger ça :)

25voto

Makario Points 1063

Une autre solution est de créer un Handler et après un retard à l' Runnable après la fermeture du tiroir, comme illustré ici: http://stackoverflow.com/a/18483633/769501. L'avantage avec cette approche est que vos fragments seront remplacées beaucoup plus tôt que ce qu'ils seraient si vous avez attendu DrawerListener#onDrawerClosed(), mais bien sûr, l'arbitraire, le retard n'est pas garantie à 100% le tiroir de l'animation sera terminé dans les délais.

Cela dit, j'utilise un 200ms et ça fonctionne à merveille.

private class DrawerItemClickListener implements OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
        drawerLayout.closeDrawer(drawerList);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                switchFragments(position); // your fragment transactions go here
            }
        }, 200);
    }
}

15voto

saguinav Points 261

Voici ce que je fais pour obtenir une animation de transaction fluide similaire à celle de l'application Gmail:

activity_drawer.xml

 <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- The navigation drawer -->
    <ListView 
    android:id="@+id/left_drawer"
        android:layout_width="280dp"
        android:layout_height="match_parent"
        android:layout_gravity="left"
        android:choiceMode="singleChoice" />

</android.support.v4.widget.DrawerLayout>
 

DrawerActivity.java

 private Fragment mContentFragment;
private Fragment mNextContentFragment;
private boolean mChangeContentFragment = false;

private Handler mHandler = new Handler();

...

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mDrawerLayout.setDrawerListener(new DrawerListener());

    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

    ...
}

....

private class DrawerItemClickListener implements ListView.OnItemClickListener {

    @Override
    public void onItemClick(AdapterView parent, View view, int position, long id) {
        getSupportFragmentManager().beginTransaction().remove(mContentFragment).commit();

        switch (position) {
            case 0:
                mNextContentFragment = new Fragment1();
                break;

            case 1:
                mNextContentFragment = new Fragment2();
                break;

            case 2:
                mNextContentFragment = new Fragment3();
                break;
        }

        mChangeContentFragment = true;

        mDrawerList.setItemChecked(position, true);

        mHandler.postDelayed(new Runnable() {

            @Override
            public void run() {
                mDrawerLayout.closeDrawer(mDrawerList);
            }           
        }, 150);
    }
}

private class DrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {

    @Override
    public void onDrawerClosed(View view) {
        if (mChangeContentFragment) {
             getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_frame, mNextContentFragment).commit();

             mContentFragment = mNextContentFragment;           
             mNextContentFragment = null;

             mChangeContentFragment = false;
         }
     }
 }
 

J'espère que ça vous aide! :-)

5voto

user1282637 Points 469

Je sais que cette question est ancienne, mais j'ai rencontré le même problème et je me suis dit que je publierais ma solution car je pense que c'est une meilleure implémentation que d'ajouter un délai de traitement codé en dur. Ce que j'ai fait est d'utiliser la fonction onDrawerClosed pour vérifier que le tiroir est bien fermé avant de faire ma tâche.

 //on button click...
private void displayView(int position) {
    switch (position) {
    //if item 1 is selected, update a global variable "int itemPosition" to be 1
    case 1:
        itemPosition = 1;
        //();
        break;
    default:
        break;
    }

    // update selected item and title, then close the drawer
    mDrawerList.setItemChecked(position, true);
    mDrawerList.setSelection(position);
    mDrawerLayout.closeDrawer(mDrawerList); //close drawer
}
 

puis dans onDrawerClosed, ouvrez l'activité correspondante.

 public void onDrawerClosed(View view) {
    getSupportActionBar().setTitle(mTitle);
    // calling onPrepareOptionsMenu() to show action bar icons
    supportInvalidateOptionsMenu();
    if (itemPosition == 1) {
        Intent intent = new Intent(BaseActivity.this, SecondActivity.class);
        startActivity(intent);
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X