DrawerLayout’s item click – Wann ist der richtige Zeitpunkt, um das Fragment zu ersetzen?

Lesezeit: 7 Minuten

Ich entwickle eine Anwendung, die das Navigationsschubladenmuster verwendet (mit DrawerLayout).

Jeder Klick auf das Element einer Schublade ersetzt das Fragment im Hauptcontainer.

Ich bin mir jedoch nicht sicher, wann der richtige Zeitpunkt für die Fragmenttransaktion ist? Wann beginnt die Schublade zu schließen? Oder nach der Schließung?

Bei google Dokumentationsbeispielkönnen Sie sehen, dass sie die Transaktion direkt nach dem Klicken auf den Artikel durchführen und dann die Schublade schließen.
Infolgedessen wirkt die Schublade träge und nicht glatt und sieht sehr schlecht aus (das passiert auch in meiner Anwendung).

Im Gmail und Google Drive Anwendungen, auf der anderen Seite, Es scheint, als würden sie die Transaktion durchführen, nachdem die Schublade geschlossen wurde (Habe ich Recht?).
Infolgedessen ist die Schublade nicht träge und sehr glatt, ABER es dauert mindestens 1 Sekunde (die Zeit, die es dauert, bis die Schublade geschlossen wird), um das nächste Fragment zu sehen.

Es scheint, dass es keine Möglichkeit gibt, dass die Schublade glatt ist, wenn sie sofort eine Fragmenttransaktion durchführt.

Was denkst du darüber?

Danke im Voraus!

  • Ich stimme zu! Ich sehe eine ruckartige Animation zum Schließen der Schublade, wenn meine App eine neue Aktivität innerhalb der Schublade startet onItemClick(). Dies liegt wahrscheinlich daran, dass im UI-Thread viele Aktivitäten stattfinden. Also muss ich jetzt eine neue Aktivität von innen starten DrawerLayout.DrawerListener stattdessen … was, wie Sie bereits erwähnt haben, die Benutzererfahrung verlangsamt.

    – Irgendwer irgendwo

    30. August 2013 um 21:38 Uhr

  • Ist es möglich, die Geschwindigkeit der Schließanimation der Schublade zu ändern? Die Geschwindigkeit scheint eine wichtige Eigenschaft zu sein, die es aufzudecken gilt … aber ich kann sie nicht in der Dokumentation finden!) developer.android.com/reference/android/support/v4/widget/…

    – Irgendwer irgendwo

    30. August 2013 um 21:47 Uhr

  • @SomeoneSomewhere Sie können die Animationslänge ändern, aber es ist keineswegs eine elegante Lösung: stackoverflow.com/questions/19460683/…

    – Makario

    21. Januar 2014 um 21:38 Uhr

  • @SomeoneSomewhere Ich mag die ruckartige Schließanimation nicht, aber ich mag es nicht, den Benutzer noch länger warten zu lassen.

    – das Blang

    8. Mai 2014 um 13:56 Uhr

  • Sie können sich diese Lösung ansehen: stackoverflow.com/a/32455989/879154

    – Quentin G.

    8. September 2015 um 10:59 Uhr

Ja, ich könnte nicht mehr zustimmen, die Durchführung einer Fragment-Transaktion (mit Ansicht) führt zu einem Layout-Pass, der zu ruckeligen Animationen bei animierten Ansichten führt, zitiert DrawerLayout Dokumente:

DrawerLayout.DrawerListener kann verwendet werden, um den Zustand und die Bewegung von Schubladenansichten zu überwachen. Vermeiden Sie kostspielige Operationen wie das Layout während der Animation, da dies zu Stottern führen kann; Versuchen Sie, während des Zustands STATE_IDLE kostspielige Operationen auszuführen.

Führen Sie also bitte Ihre Fragmenttransaktionen durch, nachdem die Schublade geschlossen ist, oder jemand patcht die Support-Bibliothek, um das irgendwie zu beheben 🙂

  • Ist es nur die Support-Bibliothek, die unter diesem Problem leidet?

    – das Blang

    8. Mai 2014 um 13:19 Uhr

  • Wie kann gewartet werden, bis sich der Status in STATE_IDLE ändert?

    – Nabil London

    3. März 2017 um 23:53 Uhr

Benutzer-Avatar
Makario

Eine andere Lösung besteht darin, eine Handler und verspätet posten Runnable nachdem Sie die Schublade geschlossen haben, wie hier gezeigt: https://stackoverflow.com/a/18483633/769501. Der Vorteil bei diesem Ansatz besteht darin, dass Ihre Fragmente viel früher ersetzt werden, als wenn Sie warten würden DrawerListener#onDrawerClosed()aber natürlich garantiert die willkürliche Verzögerung nicht zu 100%, dass die Schubladenanimation rechtzeitig fertig wird.

Das heißt, ich verwende eine Verzögerung von 200 ms und es funktioniert wunderbar.

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

  • dieser Ansatz erzeugt ein weiteres beschriebenes Problem hier

    – Verrückter Entwickler

    2. Dezember 2014 um 9:39 Uhr

  • Stürzt ab, wenn das Commit ausgeführt wird, und drückt dann auf das Aufgabenmenü

    – Sheychan

    28. Oktober 2015 um 6:22 Uhr

  • Sie Sir, sind ein Lebensretter 😀

    – Kushan

    9. Juli 2016 um 14:25 Uhr

Benutzer-Avatar
Saguinav

Dies ist, was ich tue, um eine reibungslose Transaktionsanimation ähnlich der Gmail-App zu erreichen:

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;
         }
     }
 }

Hoffe das hilft dir! 🙂

  • Ich mag diese Lösung, aber ich weiß nicht wirklich, wie ich das Backstack-Verhalten zum Laufen bringen soll. Ich könnte “addToBackStack” zur Ersetzungstransaktion hinzufügen, aber das funktioniert nicht wie erwartet, da der vorherige Inhalt entfernt wurde. Ich habe versucht, zu verstecken, anstatt zu entfernen, aber das funktioniert auch nicht.

    – pqvst

    13. Oktober 2013 um 11:36 Uhr

  • @pbergqvist Was Sie tun könnten, um das Backstack-Verhalten zu erhalten, ist: 1. Verwenden Sie eine andere Variable, um das “alte Inhaltsfragment” zu speichern, bevor Sie es entfernen. 2. Überschreiben Sie die onBackPressed-Methode aus Ihrer Aktivität und ersetzen Sie dort das Inhaltsfragment durch Ihr “altes Inhaltsfragment”.

    – Saguinav

    14. Oktober 2013 um 15:18 Uhr


  • @pbergqvist etwas noch besseres. Wenn Sie die Transaktion „Fragment entfernen“, „mChangeContentFragment=true“ und den Handler-Post zusammen in eine Methode namens „setContentFragment(Fragment fragment)“ einfügen, können Sie diese Methode in „onBackPressed“ verwenden, um denselben Code nicht zweimal neu zu schreiben. Funktioniert es für Sie?

    – Saguinav

    14. Oktober 2013 um 15:25 Uhr


  • Ich denke, das würde funktionieren, aber nur einen Schritt zurück. Sonst müsste ich den Stack selbst pflegen.

    – pqvst

    14. Oktober 2013 um 19:01 Uhr

  • Der Backstack sollte nicht geändert werden müssen – keines der App-Switch-Fragmente von Google über die Zurück-Schaltfläche. Das ist verwirrend.

    – Matthew Reilly

    14. Oktober 2013 um 23:35 Uhr

Benutzer-Avatar
Benutzer1282637

Ich weiß, dass diese Frage alt ist, aber ich bin auf dasselbe Problem gestoßen und dachte, ich würde meine Lösung posten, da ich denke, dass es eine bessere Implementierung ist, als eine fest codierte Verzögerungszeit hinzuzufügen. Was ich tat, war die Verwendung onDrawerClosed Funktion, um zu überprüfen, ob die Schublade geschlossen ist, bevor ich meine Aufgabe erledige.

//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
}

und dann hinein onDrawerClosedöffnen Sie die entsprechende Aktivität.

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

Schreiben Sie einfach Ihren Code in einen Handler und geben Sie eine Verzögerung von 200 ms ein.

 new Handler().postDelayed(new Runnable() {
  @Override
   public void run() {
       openSelectionDrawerItem(position);          
   }
 }, 200);

Benutzer-Avatar
mco

Anstatt Ihre Artikelklicks zu verzögern, was dazu führen kann, dass sich Ihre App langsam anfühlt. Ich würde nur das Schließen des mDrawerLayout verzögern. Ich würde die nicht verwenden DrawerLayout.OnDrawerListener onClose(...) entweder, weil diese Rückrufe so langsam aufgerufen werden.

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        mDrawerLayout.closeDrawer(GravityCompat.START);
    }
}, 200);

Benutzer-Avatar
Nesreteip

Wer es flüssig und ohne Verzögerung möchte, lässt die Schublade offen und schließt sie anschließend bei der Rückkehr (in der Methode onRestart()).

@Override
protected void onRestart() {
    // TODO Auto-generated method stub
    super.onRestart();
    mDrawerLayout.closeDrawer(mDrawerList);     
}

Der Nebeneffekt ist eine (schnelle) Animation bei der Rückkehr, aber das könnte akzeptabel sein.

  • Rückkehr von was? Ich möchte nur, dass sich die Schublade schließt und mein Bildschirm zu einer anderen Aktivität wechselt.

    – IgorGanapolsky

    8. Juni 2015 um 19:28 Uhr

  • @Igor Die Schublade ist immer noch geöffnet, nachdem Sie von einer anderen Aktivität mit der Zurück-Schaltfläche zurückgekehrt sind (oder eine andere Methode, mit der Sie zur Aktivität zurückkehren können, ohne sie neu zu erstellen).

    – Lorne Laliberte

    10. Juli 2015 um 22:28 Uhr

1035820cookie-checkDrawerLayout’s item click – Wann ist der richtige Zeitpunkt, um das Fragment zu ersetzen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy