Przełączanie między obrazem szuflady nawigacyjnej Androida a karetką w górę podczas korzystania z fragmentów

Podczas korzystania z szuflady nawigacyjnej twórcy Androida zalecają, aby w pasku działań "tylko te ekrany, które są reprezentowane w szufladzie nawigacyjnej, miały rzeczywiście obraz szuflady nawigacyjnej" i " wszystkie inne ekrany mają tradycyjny Karat."

Zobacz tutaj po szczegóły: http://youtu.be/F5COhlbpIbY

Używam jednego działania do kontrolowania wielu poziomów fragmentów i mogę uzyskać obraz szuflady nawigacyjnej do wyświetlania i działania w ogóle poziomy.

Podczas tworzenia fragmentów niższego poziomu mogę wywołać ActionBarDrawerToggle setDrawerIndicatorEnabled(false) aby ukryć obraz szuflady nawigacyjnej i wyświetlić karetkę do góry

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

Problem, który mam, polega na tym, że gdy wracam do fragmentów najwyższego poziomu, który nadal pokazuje Karat, zamiast oryginalnego obrazu szuflady nawigacyjnej. Jakieś sugestie, jak "odświeżyć" pasek akcji na górnych fragmentach, aby ponownie wyświetlić obraz szuflady nawigacyjnej?


Rozwiązanie

Tom ' s sugestia zadziałała. Oto co zrobiłem:

Główna aktywność

Ta aktywność kontroluje wszystkie fragmenty w aplikacji.

Przygotowując nowe fragmenty do zastąpienia innych, ustawiam DrawerToggle setDrawerIndicatorEnabled(false) tak:

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

Następnie, w nadpisaniu onBackPressed, przywróciłem powyższe, ustawiając DrawerToggle na setDrawerIndicatorEnabled(true) w następujący sposób:

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

In The LowerLevelFragments

We fragmentach zmodyfikowałem onCreate i onOptionsItemSelected tak:

W onCreate dodano setHasOptionsMenu(true), aby włączyć konfigurację menu opcji. Również ustawić setDisplayHomeAsUpEnabled(true), aby włączyć W actionbar:

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

Następnie w onOptionsItemSelected gdy Po naciśnięciu wywołuje onBackPressed() z aktywności, aby przesunąć się o jeden poziom w hierarchii i wyświetlić obraz szuflady nawigacyjnej:

@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;
        … 
    }
Author: JJD, 2013-06-23

12 answers

Napisałeś, że aby zaimplementować fragmenty niższego poziomu, zastępujesz istniejący fragment, w przeciwieństwie do implementacji fragmentu niższego poziomu w nowej aktywności.

Myślę, że będziesz musiał zaimplementować funkcję back ręcznie: gdy użytkownik naciśnie wstecz, masz kod, który wyskakuje ze stosu (np. w Activity::onBackPressed override). Więc gdziekolwiek to zrobisz, możesz odwrócić setDrawerIndicatorEnabled.

 27
Author: Tom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-27 10:42:01

To proste jak 1-2-3.

Jeśli chcesz osiągnąć:

1) Wskaźnik szuflady - gdy w tylnym stosie nie znajdują się żadne fragmenty lub szuflada jest otwarta

2) Strzałka - gdy niektóre fragmenty znajdują się w tylnym stosie

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) oba wskaźniki działają zgodnie z ich kształtem

@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. Zobacz Tworzenie szuflady nawigacyjnej dla programistów Androida na inne wskazówki dotyczące zachowania wskaźnika 3-liniowego.

 83
Author: riwnodennyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-15 11:44:23

I ' ve used next thing:

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
Author: Yuriy Sych,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-23 09:44:38

Jeśli przycisk paska akcji w górę nie działa, nie zapomnij dodać słuchacza:

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

Mam pewien problem z zaimplementowaniem nawigacji szuflady z przyciskiem home, wszystko działało oprócz akcji buton.

 12
Author: Burrich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-14 21:52:31

Spróbuj obsłużyć wybór pozycji głównej w głównej aktywności w zależności od stanu DrawerToggle. W ten sposób nie musisz dodawać tego samego kodu do każdego fragmentu.

@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
Author: dzeikei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-02 02:33:37

FOLLOW UP

Rozwiązanie podane przez @ dzeikei jest schludne, ale można je rozszerzyć, używając fragmentów, aby automatycznie obsłużyć ustawienie wskaźnika szuflady, gdy tylny ster jest pusty.

@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

Na pytanie @JJD.

Fragmenty są przechowywane/zarządzane w działaniu. Powyższy kod jest napisany raz w tej czynności, ale obsługuje tylko karetkę do onOptionsItemSelected.

W jednej z moich aplikacji musiałem również obsługiwać zachowanie karetki w górę po naciśnięciu przycisku Wstecz. Może to być obsługiwane przez nadpisanie onBackPressed.

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

Zwróć uwagę na powielanie kodu pomiędzy onOptionsItemSelected i onBackPressed, którego można uniknąć, tworząc metodę i wywołując ją w obu miejscach.

UWAGA dodaję jeszcze dwa razy executePendingTransactions co w moim przypadku było wymagane lub miałem czasami dziwne zachowania karetki.

 7
Author: HpTerm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 10:21:22

Stworzyłem interfejs dla aktywności hostingowej, aby zaktualizować stan widoku menu hamburgera. Dla fragmentów najwyższego poziomu ustawiam przełącznik na true, a dla fragmentów, dla których chcę wyświetlić strzałkę w górę 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);
    }
}
Potem w mojej działalności ...
public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {

    private ActionBarDrawerToggle mDrawerToggle;

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

}
 2
Author: Bill Mote,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-05 01:20:42

Ta odpowiedź działała, ale był z tym mały problem. getSupportActionBar().setDisplayHomeAsUpEnabled(false) nie został wywołany jawnie i powodował, że ikona szuflady była ukryta nawet wtedy, gdy w backstacku nie było przedmiotów, więc zmiana metody setActionBarArrowDependingOnFragmentsBackStack() zadziałała dla mnie.

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
Author: Sheraz Ahmad Khilji,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:27

Logika jest jasna. Show back button if fragment back stack is clear. Pokaż animację materiału, jeśli stos fragmentów nie jest jasny.

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
Author: kml_ckr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-07 12:58:25

Jeśli spojrzysz na aplikację GMAIL i przyjdziesz tutaj, aby wyszukać ikonę carret/affordance..

Proszę Cię o to, żadna z powyższych odpowiedzi nie była jasna. udało mi się zmodyfikować zaakceptowaną odpowiedź.
  • NavigationDrawer -- > Listview zawiera podfragmenty.


  • Subfragmenty będą wymienione w następujący sposób

  • FirstFragment = = position 0 - - - > this will have subfragments --> fragment

  • secondFragment
  • trzecia część i tak dalej....

W firstFragment masz inny fragment.

Call this on DrawerActivity

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

I we fragmencie

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

W metodzie aktywności szuflady OnBackPressed ustaw przełącznik szuflady na true, aby ponownie włączyć ikonę listy nawigacji.

Dzięki, Pusp

 1
Author: Puspharaj Selvaraj,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-10 03:35:28

Możesz spojrzeć na ten mały przykład! https://github.com/oskarko/NavDrawerExample

 1
Author: oskarko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-26 15:56:21

IMO, użycie onnavigateup () (jak pokazano tutaj) w rozwiązaniu riwnodennyka lub Toma jest czystsze i wydaje się działać lepiej. Po prostu zastąp kod onOptionsItemSelected tym:

@Override
public boolean onSupportNavigateUp() {
    if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
        // handle up navigation
        return true;
    } else {
        return super.onSupportNavigateUp();
    }
}
 0
Author: 0101100101,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:05