it-swarm.com.de

Wechseln zwischen Android Navigation Drawer Image und Up Caret, wenn Fragmente verwendet werden

Bei Verwendung der Navigationsleiste empfehlen die Entwickler von Android=), dass in der Aktionsleiste "nur die Bildschirme, die in der Navigationsleiste dargestellt werden, das Bild der Navigationsleiste enthalten sollten" und dass "alle anderen Bildschirme das Bild der Navigationsleiste enthalten" traditionelles Karat. "

Einzelheiten finden Sie hier: http://youtu.be/F5COhlbpIbY

Ich verwende eine Aktivität, um mehrere Ebenen von Fragmenten zu steuern, und kann das Navigationsschubladenbild auf allen Ebenen anzeigen und funktionieren lassen.

Bei der Erstellung von Fragmenten niedrigerer Ebene kann ich die Funktion ActionBarDrawerTogglesetDrawerIndicatorEnabled(false) aufrufen, um das Bild der Navigationsleiste auszublenden und das Aufwärts-Caret anzuzeigen

LowerLevelFragment lowFrag = new LowerLevelFragment();

//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout, 
lowFrag, "lowerFrag").addToBackStack(null).commit();

Das Problem, das ich habe, ist, wenn ich zurück zu den Fragmenten der obersten Ebene navigiere, die in der oberen Karat anstelle des ursprünglichen Navigationsschubladenbilds angezeigt werden. Haben Sie Vorschläge, wie Sie die ActionBar auf den Fragmenten der obersten Ebene "aktualisieren" können, um das Bild der Navigationsleiste wieder anzuzeigen?


Lösung

Toms Vorschlag hat für mich funktioniert. Folgendes habe ich getan:

Hauptaktivität

Diese Aktivität steuert alle Fragmente in der App.

Wenn ich neue Fragmente vorbereite, um andere zu ersetzen, setze ich DrawerToggle setDrawerIndicatorEnabled(false) wie folgt:

LowerLevelFragment lowFrag = new LowerLevelFragment();

//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout,   
lowFrag).addToBackStack(null).commit();

Als nächstes habe ich in einer Überschreibung von onBackPressed das Obige zurückgesetzt, indem ich DrawerToggle auf setDrawerIndicatorEnabled(true) gesetzt habe:

@Override
public void onBackPressed() {
    super.onBackPressed();
    // turn on the Navigation Drawer image; 
    // this is called in the LowerLevelFragments
    setDrawerIndicatorEnabled(true)
}

In den LowerLevelFragments

In den Fragmenten habe ich onCreate und onOptionsItemSelected folgendermaßen modifiziert:

In onCreatesetHasOptionsMenu(true) hinzugefügt, um die Konfiguration des Optionsmenüs zu ermöglichen. Stellen Sie auch setDisplayHomeAsUpEnabled(true) ein, um das zu aktivieren < in der actionleiste:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // needed to indicate that the fragment would 
    // like to add items to the Options Menu        
    setHasOptionsMenu(true);    
    // update the actionbar to show the up carat/affordance 
    getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}

Dann in onOptionsItemSelected, wann immer die < wird gedrückt, ruft es die Funktion onBackPressed() aus der Aktivität auf, um in der Hierarchie eine Ebene nach oben zu gelangen und das Navigationsbild anzuzeigen:

@Override
public boolean onOptionsItemSelected(MenuItem item) {   
    // Get item selected and deal with it
    switch (item.getItemId()) {
        case Android.R.id.home:
            //called when the up affordance/carat in actionbar is pressed
            getActivity().onBackPressed();
            return true;
        … 
    }
177
EvilAsh

Sie haben geschrieben, dass Sie zum Implementieren von Fragmenten niedrigerer Ebene das vorhandene Fragment ersetzen und nicht das Fragment niedrigerer Ebene in einer neuen Aktivität implementieren.

Ich würde denken, dass Sie dann die Back-Funktionalität manuell implementieren müssten: Wenn der Benutzer zurückgedrückt hat, haben Sie Code, der den Stack öffnet (z. B. in Activity::onBackPressed überschreiben). Wo immer Sie das tun, können Sie setDrawerIndicatorEnabled umkehren.

28
Tom

Es ist einfach wie 1-2-3.

Wenn Sie erreichen wollen:

1) Schubladenanzeige - wenn sich keine Fragmente im hinteren Stapel befinden oder die Schublade geöffnet ist

2) Pfeil - wenn sich einige Fragmente im hinteren Stapel befinden

private FragmentManager.OnBackStackChangedListener
        mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
    @Override
    public void onBackStackChanged() {
        syncActionBarArrowState();
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    getSupportActionBar().setDisplayShowHomeEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    mDrawerToggle = new ActionBarDrawerToggle(
            this,             
            mDrawerLayout,  
            R.drawable.ic_navigation_drawer, 
            0, 
            0  
    ) {

        public void onDrawerClosed(View view) {
            syncActionBarArrowState();
        }

        public void onDrawerOpened(View drawerView) {
            mDrawerToggle.setDrawerIndicatorEnabled(true);
        }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
    getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener);
}

@Override
protected void onDestroy() {
    getSupportFragmentManager().removeOnBackStackChangedListener(mOnBackStackChangedListener);
    super.onDestroy();
}

private void syncActionBarArrowState() {
    int backStackEntryCount = 
        getSupportFragmentManager().getBackStackEntryCount();
    mDrawerToggle.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}

3) Beide Indikatoren sollen entsprechend ihrer Form wirken

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (mDrawerToggle.isDrawerIndicatorEnabled() && 
        mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    } else if (item.getItemId() == Android.R.id.home && 
               getSupportFragmentManager().popBackStackImmediate()) {
        return true;
    } else {
        return super.onOptionsItemSelected(item);
    }
}

P.S. Siehe Erstellen einer Navigationsleiste unter Android Developers in anderen Tipps zum Verhalten der 3-Zeilen-Anzeige.

83
riwnodennyk

Ich habe folgendes verwendet:

getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
            @Override
            public void onBackStackChanged() {
                if(getSupportFragmentManager().getBackStackEntryCount() > 0){
                    mDrawerToggle.setDrawerIndicatorEnabled(false);
                    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
                }
                else {
                    getSupportActionBar().setDisplayHomeAsUpEnabled(false);
                    mDrawerToggle.setDrawerIndicatorEnabled(true);
                }
            }
        });
14
Yuriy Sych

Wenn Ihre Aktionsleistenschaltfläche nicht funktioniert, vergessen Sie nicht, den Listener hinzuzufügen:

// Navigation back icon listener
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onBackPressed();
        }
});

Ich habe einige Probleme beim Implementieren einer Schubladennavigation mit einem Startknopf. Alles funktionierte außer dem Aktionsknopf.

12
Burrich

Versuchen Sie, die Home-Elementauswahl in MainActivity abhängig vom Status von DrawerToggle zu bearbeiten. Auf diese Weise müssen Sie nicht jedem Fragment denselben Code hinzufügen.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Only handle with DrawerToggle if the drawer indicator is enabled.
    if (mDrawerToggle.isDrawerIndicatorEnabled() &&
            mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle action buttons
    switch (item.getItemId()) {
        // Handle home button in non-drawer mode
        case Android.R.id.home:
            onBackPressed();
            return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}
10
dzeikei

FOLLOW UP

Die von @dzeikei gegebene Lösung ist ordentlich, kann aber bei Verwendung von Fragmenten erweitert werden, um das automatische Zurücksetzen der Schubladenanzeige zu handhaben, wenn der Rückstapel leer ist.

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Only handle with DrawerToggle if the drawer indicator is enabled.
    if (mDrawerToggle.isDrawerIndicatorEnabled() &&
            mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle action buttons
    switch (item.getItemId()) {
        // Handle home button in non-drawer mode
        case Android.R.id.home:
            // Use getSupportFragmentManager() to support older devices
            FragmentManager fragmentManager = getFragmentManager();
            fragmentManager.popBackStack();
            // Make sure transactions are finished before reading backstack count
            fragmentManager.executePendingTransactions();
            if (fragmentManager.getBackStackEntryCount() < 1){
                mDrawerToggle.setDrawerIndicatorEnabled(true);  
            }
            return true;

        default:
            return super.onOptionsItemSelected(item);
    }
}

EDIT

Für die Frage von @JJD.

Die Fragmente werden in einer Aktivität gehalten/verwaltet. Der obige Code wird einmal in dieser Aktivität geschrieben, behandelt aber nur das Aufwärts-Caret für das onOptionsItemSelected.

In einer meiner Apps musste ich auch das Verhalten der oberen Einfügemarke regeln, wenn der Zurück-Knopf gedrückt wurde. Dies kann durch Überschreiben von onBackPressed behoben werden.

@Override
public void onBackPressed() {
    // Use getSupportFragmentManager() to support older devices
    FragmentManager fragmentManager = getFragmentManager();
    fragmentManager.executePendingTransactions();
    if (fragmentManager.getBackStackEntryCount() < 1){
        super.onBackPressed();
    } else {
        fragmentManager.executePendingTransactions();
        fragmentManager.popBackStack();
        fragmentManager.executePendingTransactions();
        if (fragmentManager.getBackStackEntryCount() < 1){
            mDrawerToggle.setDrawerIndicatorEnabled(true);
        }
    }
};

Beachten Sie die Codeduplizierung zwischen onOptionsItemSelected und onBackPressed, die vermieden werden kann, indem eine Methode erstellt und an beiden Stellen aufgerufen wird.

Beachten Sie auch, dass ich zwei weitere Male executePendingTransactions hinzufüge, was in meinem Fall erforderlich war, oder dass ich manchmal seltsame Verhaltensweisen der oberen Schicht hatte.

6
HpTerm

Ich habe eine Schnittstelle für die Hosting-Aktivität erstellt, um den Ansichtsstatus des Hamburger-Menüs zu aktualisieren. Für Fragmente der obersten Ebene setze ich den Umschalter auf true und für Fragmente, für die ich den Pfeil nach oben <anzeigen möchte, setze ich den Umschalter auf false.

public class SomeFragment extends Fragment {

    public interface OnFragmentInteractionListener {
        public void showDrawerToggle(boolean showDrawerToggle);
    }

    private OnFragmentInteractionListener mListener;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            this.mListener = (OnFragmentInteractionListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        mListener.showDrawerToggle(false);
    }
}

Dann in meiner Aktivität ...

public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {

    private ActionBarDrawerToggle mDrawerToggle;

    public void showDrawerToggle(boolean showDrawerIndicator) {
        mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator);
    }

}
2
Bill Mote

Dies Antwort hat funktioniert, aber es gab ein kleines Problem damit. Die getSupportActionBar().setDisplayHomeAsUpEnabled(false) wurde nicht explizit aufgerufen und führte dazu, dass das Schubladensymbol ausgeblendet wurde, auch wenn sich keine Elemente im Backstack befanden. Daher funktionierte die setActionBarArrowDependingOnFragmentsBackStack() -Methode für mich.

private void setActionBarArrowDependingOnFragmentsBackStack() {
        int backStackEntryCount = getSupportFragmentManager()
                .getBackStackEntryCount();
        // If there are no items in the back stack
        if (backStackEntryCount == 0) {
            // Please make sure that UP CARAT is Hidden otherwise Drawer icon
            // wont display
            getSupportActionBar().setDisplayHomeAsUpEnabled(false);
            // Display the Drawer Icon
            mDrawerToggle.setDrawerIndicatorEnabled(true);
        } else {
            // Show the Up carat
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            // Hide the Drawer Icon
            mDrawerToggle.setDrawerIndicatorEnabled(false);
        }

    }
2

Die Logik ist klar. Schaltfläche "Zurück" anzeigen, wenn der Fragment-Stapel leer ist. Zeigt eine Hamburger-Back-Animation an, wenn der Fragmentstapel nicht klar ist.

getSupportFragmentManager().addOnBackStackChangedListener(
    new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            syncActionBarArrowState();
        }
    }
);


private void syncActionBarArrowState() {
    int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
    mNavigationDrawerFragment.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}

//add these in Your NavigationDrawer fragment class

public void setDrawerIndicatorEnabled(boolean flag){
    ActionBar actionBar = getActionBar();
    if (!flag) {
        mDrawerToggle.setDrawerIndicatorEnabled(false);
        actionBar.setDisplayHomeAsUpEnabled(true);
        mDrawerToggle.setHomeAsUpIndicator(getColoredArrow());
    } else {
        mDrawerToggle.setDrawerIndicatorEnabled(true);
    }
    mDrawerToggle.syncState();
    getActivity().supportInvalidateOptionsMenu();
}

//download back button from this(https://www.google.com/design/icons/) website and add to your project

private Drawable getColoredArrow() {
    Drawable arrowDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_arrow_back_black_24dp);
    Drawable wrapped = DrawableCompat.wrap(arrowDrawable);

    if (arrowDrawable != null && wrapped != null) {
        // This should avoid tinting all the arrows
        arrowDrawable.mutate();
        DrawableCompat.setTint(wrapped, Color.GRAY);
    }
    return wrapped;
}
1
kml_ckr

Sie können sich dieses kleine Beispiel ansehen! https://github.com/oskarko/NavDrawerExample

1
oskarko

Wenn Sie sich die GMAIL-App ansehen und hier nach dem Carret/Affordable-Symbol suchen.

Ich würde Sie bitten, dies zu tun, keine der obigen Antworten war klar. Ich konnte die akzeptierte Antwort ändern.

  • NavigationDrawer -> Listenansicht enthält Unterfragmente.


  • unterfragmente werden wie folgt aufgelistet

  • firstFragment == Position 0 ---> Dies wird Unterfragmente haben -> Fragment

  • zweites Fragment
  • thirdFragment und so weiter ....

In firstFragment haben Sie ein anderes Fragment.

Rufen Sie dies in DrawerActivity auf

getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {
            if (getFragmentManager().getBackStackEntryCount() > 0) {
                mDrawerToggle.setDrawerIndicatorEnabled(false);
            } else {
                mDrawerToggle.setDrawerIndicatorEnabled(true);
            }
        }
    });

und in fragment

    setHasOptionsMenu(true);    

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Get item selected and deal with it
    switch (item.getItemId()) {
        case Android.R.id.home:
            //called when the up affordance/carat in actionbar is pressed
            activity.onBackPressed();
            return true;
    }
    return false;
}

Setzen Sie bei der Aktivitätsmethode OnBackPressed Drawer den Drawer-Schalter auf true, um das Navigationslistensymbol wieder zu aktivieren.

Danke, Pusp

1
Tot

IMO, mit onNavigateUp () (wie gezeigt hier ) in Riwnodennyk oder Toms Lösung ist sauberer und scheint besser zu funktionieren. Ersetzen Sie einfach den onOptionsItemSelected-Code durch diesen:

@Override
public boolean onSupportNavigateUp() {
    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        // handle up navigation
        return true;
    } else {
        return super.onSupportNavigateUp();
    }
}
0
0101100101