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 DrawerLayoutDokumente:
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
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
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
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);
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);
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()).
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
10358200cookie-checkDrawerLayout’s item click – Wann ist der richtige Zeitpunkt, um das Fragment zu ersetzen?yes
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 startenDrawerLayout.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