webentwicklung-frage-antwort-db.com.de

Navigationsleiste ausblenden, wenn der Benutzer die Zurück-Taste drückt

Ich habe die offiziellen Entwickler-Tutorials von Google here befolgt, um eine Navigationsleiste zu erstellen. 

Im Moment funktioniert alles einwandfrei, außer wenn der Benutzer die native Zurück-Schaltfläche verwendet, die Android am unteren Rand des Bildschirms bereitstellt (zusammen mit den Home-Tasten und den letzten Tasten der App). Wenn der Benutzer mit dieser ursprünglichen Zurück-Schaltfläche zurück navigiert, ist die Navigationsleiste weiterhin geöffnet. Wenn der Benutzer stattdessen mithilfe der Aktionsleiste zurück navigiert, wird die Navigationsleiste so geschlossen, wie ich es möchte. 

Mein Code ist fast identisch mit den offiziellen Tutorials, abgesehen davon, wie ich mit dem Benutzer umgehe, der einen Eintrag in der Schublade auswählt:

   mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener()
    {
        @Override
        public void onItemClick(AdapterView parent, View view, int position, long id)
        {
            switch(position)
            {
                case 0:
                {
                    Intent intent = new Intent(MainActivity.this, NextActivity.class);
                    startActivity(intent);
                }
            }
        }
    });

Wie kann ich die Navigationsleiste schließen lassen, wenn der Benutzer mit der ursprünglichen Zurück-Schaltfläche zurück navigiert? Jeder Rat wird geschätzt. Vielen Dank!

21
pez

Sie müssen onBackPressed () überschreiben. Aus den Dokumenten:

Wird aufgerufen, wenn die Aktivität das Drücken des Benutzers auf die Rückseite erkannt hat Schlüssel. Die Standardimplementierung beendet einfach die aktuelle Aktivität Sie können dies jedoch überschreiben, um zu tun, was Sie möchten.

So können Sie Code wie folgt haben:

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

Wenn diese Methode geöffnet ist, wird sie auf das Standardverhalten zurückgesetzt.

54
mt0s

Sie müssen onBackPressed() in Ihrer Aktivität überschreiben und prüfen, ob die Navigationsleiste geöffnet ist. Wenn es geöffnet ist, schließen Sie es, andernfalls führen Sie eine normale, zurückgedrückte Methode aus. Hier ist etwas Code, der mit einem Pseudocode gemischt ist, um Ihnen zu helfen:

@Override
public void onBackPressed(){
  if(drawer.isDrawerOpen()){ //replace this with actual function which returns if the drawer is open
   drawer.close();     // replace this with actual function which closes drawer
  }
  else{
   super.onBackPressed();
  }
}

Um den Pseudocode zu ersetzen, sehen Sie in der Dokumentation der Schublade nach. Ich weiß, dass beide Methoden existieren. 

10
qazimusab

AKTUALISIEREN:

Ab der Support Library 24.0.0 ist dies ohne Umgehung möglich. Es wurden zwei neue openDrawer und closeDrawer Methods hinzugefügt zu DrawerLayout, mit denen die Schublade ohne Animation geöffnet oder geschlossen werden kann.

Jetzt können Sie openDrawer(drawerView, false) und closeDrawer(drawerView, false) verwenden, um die Schublade ohne Verzögerung zu öffnen und zu schließen.


Wenn Sie startActivity() aufrufen, ohne closeDrawer() aufzurufen, wird die Schublade in dieser Instanz der Aktivität geöffnet, wenn Sie mit der Zurück-Taste dorthin navigieren. Beim Aufruf von closeDrawer() beim Aufruf von startActivity() gibt es verschiedene Probleme, die von abgehackten Animationen bis zu einer langen Wahrnehmungsverzögerung reichen, abhängig von der verwendeten Problemumgehung. Ich stimme zu, dass der beste Ansatz ist, einfach startActivity() aufzurufen und die Schublade nach der Rückkehr zu schließen.

Damit dies funktioniert, müssen Sie die Schublade ohne Animation schließen, wenn Sie mit der Zurück-Taste zurück zur Aktivität navigieren. (Eine relativ verschwenderische Problemumgehung wäre, die Aktivität beim Zurücknavigieren zu recreate() zu erzwingen, es ist jedoch möglich, dies zu lösen, ohne dies zu tun.)

Sie müssen auch sicherstellen, dass Sie die Schublade nur schließen, wenn Sie nach der Navigation zurückkehren und nicht nach einer Orientierungsänderung. Dies ist jedoch ganz einfach.


Einzelheiten

(Sie können über diese Erklärung hinausgehen, wenn Sie nur den Code sehen möchten.)

Obwohl der Aufruf von closeDrawer() von onCreate() dazu führt, dass die Schublade ohne Animationen geschlossen wird, gilt dies nicht für onResume(). Wenn Sie closeDrawer() von onResume() aufrufen, wird die Schublade mit einer Animation geschlossen, die für den Benutzer momentan sichtbar ist. DrawerLayout bietet keine Methode zum Schließen der Schublade ohne diese Animation, es ist jedoch möglich, sie zu erweitern, um eine hinzuzufügen.

Wenn Sie die Schublade schließen, wird sie einfach vom Bildschirm weggeschoben, sodass Sie die Animation effektiv überspringen können, indem Sie die Schublade direkt in die "geschlossene" Position bewegen. Die Übersetzungsrichtung hängt von der Schwerkraft ab (unabhängig davon, ob es sich um eine linke oder rechte Schublade handelt), und die genaue Position hängt von der Größe der Schublade ab, sobald sie mit allen ihren Kindern ausgelegt ist.

Das einfache Verschieben reicht jedoch nicht aus, da DrawerLayout einen internen Zustand in erweiterter LayoutParams beibehält, anhand dessen ermittelt wird, ob die Schublade geöffnet ist. Wenn Sie die Schublade nur aus dem Bildschirm verschieben, wird sie nicht wissen, dass sie geschlossen ist. Dies führt zu anderen Problemen. (Zum Beispiel wird die Schublade bei der nächsten Orientierungsänderung wieder angezeigt.)

Da Sie die Unterstützungsbibliothek in Ihre App kompilieren, können Sie im Android.support.v4.widget-Paket eine Klasse erstellen, um Zugriff auf die standardmäßigen (package-private) Teile zu erhalten, oder erweitern Sie DrawerLayout, ohne eine der anderen erforderlichen Klassen zu kopieren. Dadurch wird auch die Aktualisierung Ihres Codes bei zukünftigen Änderungen der Support-Bibliothek reduziert. (Es ist immer am besten, Ihren Code so gut wie möglich von den Implementierungsdetails zu isolieren.) Sie können moveDrawerToOffset() verwenden, um die Schublade zu verschieben, und die LayoutParams so einstellen, dass die Schublade geschlossen wird.


Code

Dies ist der Code, der die Animation überspringt:

        // move drawer directly to the closed position
        moveDrawerToOffset(drawerView, 0.f); 

        // set internal state so DrawerLayout knows it's closed
        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;

        invalidate();

Hinweis: Wenn Sie nur moveDrawerToOffset() aufrufen, ohne die LayoutParams zu ändern, bewegt sich die Schublade bei der nächsten Orientierungsänderung wieder in die geöffnete Position.


Option 1 (vorhandenes DrawerLayout verwenden)

Dieser Ansatz fügt dem Paket support.v4 eine Dienstprogrammklasse hinzu, um auf die Paket-privaten Teile zuzugreifen, die wir in DrawerLayout benötigen.

Legen Sie diese Klasse in/src/Android/support/v4/widget /:

package Android.support.v4.widget;

import Android.support.annotation.IntDef;
import Android.support.v4.view.GravityCompat;
import Android.view.Gravity;
import Android.view.View;

import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

public class Support4Widget {

    /** @hide */
    @IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
    @Retention(RetentionPolicy.SOURCE)
    private @interface EdgeGravity {}

    public static void setDrawerClosed(DrawerLayout drawerLayout, @EdgeGravity int gravity) {
        final View drawerView = drawerLayout.findDrawerWithGravity(gravity);
        if (drawerView == null) {
            throw new IllegalArgumentException("No drawer view found with gravity " +
                    DrawerLayout.gravityToString(gravity));
        }

        // move drawer directly to the closed position
        drawerLayout.moveDrawerToOffset(drawerView, 0.f); 

        // set internal state so DrawerLayout knows it's closed
        final DrawerLayout.LayoutParams lp = (DrawerLayout.LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;

        drawerLayout.invalidate();
    }
}

Legen Sie in Ihrer Aktivität einen booleschen Wert fest, wenn Sie sich fortbewegen, um anzugeben, dass die Schublade geschlossen sein soll:

public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER";
private boolean mCloseNavDrawer;

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    if (savedInstanceState != null) {
        mCloseNavDrawer = savedInstanceState.getBoolean(CLOSE_NAV_DRAWER);
    }
}

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {

    // ...

    startActivity(intent);
    mCloseNavDrawer = true;
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putBoolean(CLOSE_NAV_DRAWER, mCloseNavDrawer);
    super.onSaveInstanceState(savedInstanceState);
}   

... und verwenden Sie die setDrawerClosed()-Methode, um die Schublade in onResume() ohne Animation zu schließen:

@Overrid6e
protected void onResume() {
    super.onResume();

    if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        Support4Widget.setDrawerClosed(mDrawerLayout, GravityCompat.START);
        mCloseNavDrawer = false;
    }
}

Option 2 (von DrawerLayout ausgehend)

Dieser Ansatz erweitert DrawerLayout um die Methode setDrawerClosed ().

Legen Sie diese Klasse in/src/Android/support/v4/widget /:

package Android.support.v4.widget;

import Android.content.Context;
import Android.support.annotation.IntDef;
import Android.support.v4.view.GravityCompat;
import Android.util.AttributeSet;
import Android.view.Gravity;
import Android.view.View;

import Java.lang.annotation.Retention;
import Java.lang.annotation.RetentionPolicy;

public class CustomDrawerLayout extends DrawerLayout {

    /** @hide */
    @IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
    @Retention(RetentionPolicy.SOURCE)
    private @interface EdgeGravity {}

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

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

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

    public void setDrawerClosed(View drawerView) {
        if (!isDrawerView(drawerView)) {
            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
        }

        // move drawer directly to the closed position
        moveDrawerToOffset(drawerView, 0.f); 

        // set internal state so DrawerLayout knows it's closed
        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;

        invalidate();
    }

    public void setDrawerClosed(@EdgeGravity int gravity) {
        final View drawerView = findDrawerWithGravity(gravity);
        if (drawerView == null) {
            throw new IllegalArgumentException("No drawer view found with gravity " +
                    gravityToString(gravity));
        }

        // move drawer directly to the closed position
        moveDrawerToOffset(drawerView, 0.f); 

        // set internal state so DrawerLayout knows it's closed
        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
        lp.onScreen = 0.f;
        lp.knownOpen = false;

        invalidate();
    }
}

Verwenden Sie CustomDrawerLayout anstelle von DrawerLayout in Ihren Aktivitätslayouts:

<Android.support.v4.widget.CustomDrawerLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true"
    >

... und legen Sie in Ihrer Aktivität einen booleschen Wert fest, wenn Sie weg navigieren, um anzugeben, dass die Schublade geschlossen sein sollte:

public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER";
private boolean mCloseNavDrawer;

@Override
public void onCreate(Bundle savedInstanceState) {
    // ...
    if (savedInstanceState != null) {
        mCloseNavDrawer = savedInstanceState.getBoolean(CLOSE_NAV_DRAWER);
    }
}

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {

    // ...

    startActivity(intent);
    mCloseNavDrawer = true;
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putBoolean(CLOSE_NAV_DRAWER, mCloseNavDrawer);
    super.onSaveInstanceState(savedInstanceState);
}   

... und verwenden Sie die setDrawerClosed()-Methode, um die Schublade in onResume() ohne Animation zu schließen:

@Overrid6e
protected void onResume() {
    super.onResume();

    if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
        mDrawerLayout.setDrawerClosed(GravityCompat.START);
        mCloseNavDrawer = false;
    }
}
4
Lorne Laliberte

Hier ist eine alternative Lösung für Ihr Problem.

@Override    
public void onBackPressed(){    
    if(drawerLayout.isDrawerOpen(navigationView)){    
        drawerLayout.closeDrawer(navigationView);    
    }else {    
        finish();    
    }    
}    
3

Die Implementierung der von @James Cross bereitgestellten Antwort funktionierte, aber die Animation zum Schließen der Schublade war unerwünscht und konnte ohne viel Aufwand nicht behoben werden: example .

@Override
public void onResume()
{
    super.onResume();
    mDrawerLayout.closeDrawers();
}

Um dies zu umgehen, starten Sie die Aktivität erneut, wenn Sie die Rücktaste des Geräts drücken. Es scheint mir nicht ideal, aber es funktioniert. Überschreiben von onBackPressed(), wie von @ mt0s und @Qazi Ahmed vorgeschlagen, und Bestimmen eines Zusatzes zur Ermittlung der Anrufaktivität:

    mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener()
    {
        @Override
        public void onItemClick(AdapterView parent, View view, int position, long id)
        {
            switch(position)
            {
                case 0:
                {
                    Intent intent = new Intent(MainActivity.this, NextActivity.class);
                    //pass int extra to determine calling activity
                    intent.putExtra(EXTRA_CALLING_ACTIVITY, CallingActivityInterface.MAIN_ACTIVITY);
                    startActivity(intent);
                }
            }
        }
    });

Überprüfen Sie in NextActivity.class die aufrufende Aktivität:

@Override
public void onBackPressed()
{
    int callingActivity = getIntent().getIntExtra(EXTRA_CALLING_ACTIVITY, CallingActivityInterface.MAIN_ACTIVITY);
    switch(callingActivity)
    {
        case CallingActivityInterface.MAIN_ACTIVITY:
        {
            Intent intent = new Intent(this, MainActivity.class);
            startActivity(intent);
            finish();
        }
        ...
    }
}

Auf diese Weise wird die Schublade ohne Animation geschlossen, wenn ich zu MainActivity zurückkehre. Es gibt wahrscheinlich bessere Möglichkeiten, dies zu tun. Meine App ist im Moment relativ einfach und das funktioniert, aber ich warte auf eine effektivere Methode, wenn jemand eine hat.

3
pez

Sie möchten wahrscheinlich sicherstellen, dass die Navigationsziehung beim Öffnen der Aktivität immer geschlossen ist. Verwenden Sie dies, um das zu tun:

@Override
public void onResume(){
    mDrawerList.closeDrawer(Gravity.LEFT);
}
1
James Cross

Warum der Streit? Schließen Sie einfach die Schublade, wenn Sie auf eine Schubladenposition klicken. So wird es in der offiziellen Google Play App gemacht.

private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
         drawerLayout.closeDrawer(GravityCompat.START, false);
         selectItem(position); 
    }
}
1
Damnum

einfache probe:

Schublade resultDrawer;

public void onBackPressed () {

if (this.resultDrawer.isDrawerOpen()) {    
    this.resultDrawer.closeDrawer();    
} else {    
    super.onBackPressed();    
}

}

0
Chirag Patel