Cambiar entre la imagen del cajón de navegación de Android y el caret superior al usar fragmentos
Al usar el Cajón de Navegación, los desarrolladores de Android recomiendan que en la Barra de acción "solo las pantallas que están representadas en el Cajón de Navegación deben tener la imagen del Cajón de navegación" y que "todas las demás pantallas tienen el quilate tradicional."
Vea aquí para más detalles: http://youtu.be/F5COhlbpIbY
Estoy usando una actividad para controlar múltiples niveles de fragmentos y puedo hacer que la imagen del Cajón de navegación se muestre y funcione nivel.
Al crear fragmentos de nivel inferior puedo llamar al ActionBarDrawerToggle
setDrawerIndicatorEnabled(false)
para ocultar la imagen del cajón de navegación y mostrar el icono de arriba
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();
El problema que estoy teniendo es cuando navego de nuevo a los fragmentos de nivel superior que el quilate arriba todavía muestra en lugar de la imagen del cajón de navegación original. ¿Alguna sugerencia sobre cómo" actualizar " la barra de acción en los fragmentos de nivel superior para volver a mostrar la imagen del cajón de navegación?
Solución
Tom's la sugerencia funcionó para mí. Esto es lo que hice:
Actividad principal
Esta actividad controla todos los fragmentos de la aplicación.
Al preparar nuevos fragmentos para reemplazar a otros, establezco el DrawerToggle setDrawerIndicatorEnabled(false)
de la siguiente manera:
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();
A continuación, en una anulación de onBackPressed
, revierto lo anterior estableciendo el DrawerToggle a setDrawerIndicatorEnabled(true)
de la siguiente manera:
@Override
public void onBackPressed() {
super.onBackPressed();
// turn on the Navigation Drawer image;
// this is called in the LowerLevelFragments
setDrawerIndicatorEnabled(true)
}
En los segmentos de nivel inferior
En los fragmentos que modifiqué onCreate
y onOptionsItemSelected
así: {[18]]}
En onCreate
se agregó setHasOptionsMenu(true)
para habilitar la configuración del menú de opciones. También establezca setDisplayHomeAsUpEnabled(true)
para habilitar el en la barra de acción:
@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);
}
Luego en onOptionsItemSelected
cada vez que el se pulsa llama al onBackPressed()
de la actividad para subir un nivel en la jerarquía y mostrar la Imagen del Cajón de navegación:
@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;
…
}
12 answers
Ha escrito que, para implementar fragmentos de nivel inferior, está reemplazando el fragmento existente, en lugar de implementar el fragmento de nivel inferior en una nueva actividad.
Creo que entonces tendrías que implementar la funcionalidad back manualmente: cuando el usuario presiona back tienes código que hace estallar la pila (por ejemplo, en Activity::onBackPressed
override). Así que, dondequiera que hagas eso, puedes invertir el setDrawerIndicatorEnabled
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-27 10:42:01
Es tan fácil como 1-2-3.
Si quieres lograr:
1) Indicador de cajón - cuando no hay fragmentos en la pila posterior o el cajón está abierto
2) Arrow - cuando algunos fragmentos están en la pila posterior
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) Ambos indicadores para actuar de acuerdo a su forma
@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.d. Ver Creación de un cajón de navegación en los desarrolladores de Android en otros consejos sobre el comportamiento del indicador de 3 líneas.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-15 11:44:23
He usado lo siguiente:
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);
}
}
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-23 09:44:38
Si el botón de la barra de acción ascendente no funciona, no olvides agregar el oyente:
// Navigation back icon listener
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
Tengo algunos problemas para implementar una navegación de cajón con un botón de inicio, todo funcionó excepto el botón de acción.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-14 21:52:31
Intente manejar la selección de elementos de inicio en MainActivity dependiendo del estado del DrawerToggle. De esta manera no tienes que añadir el mismo código a cada fragmento.
@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);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-02 02:33:37
SEGUIMIENTO
La solución dada por @dzeikei es ordenada, pero se puede extender, cuando se usan fragmentos, para manejar automáticamente la configuración del indicador del cajón cuando el backstack está vacío.
@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);
}
}
EDITAR
Para la pregunta de @JJD.
Los fragmentos se mantienen/administran en una actividad. El código anterior se escribe una vez en esa actividad, pero solo maneja el signo up para onOptionsItemSelected
.
En una de mis aplicaciones también necesitaba manejar el comportamiento del signo up al presionar el botón back. Esto se puede manejar sobreescribiendo 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);
}
}
};
Tenga en cuenta la duplicación de código entre onOptionsItemSelected
y onBackPressed
que se puede evitar creando un método y llamando a ese método en ambos lugares.
También tenga en cuenta que agrego dos veces más executePendingTransactions
que en mi caso se requería o de lo contrario tenía a veces comportamientos extraños del cuadro de arriba.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-28 10:21:22
He creado una interfaz para la actividad de alojamiento para actualizar el estado de vista del menú hamburguesa. Para los fragmentos de nivel superior, establezco el conmutador en true
y para los fragmentos para los que quiero mostrar la flecha hacia arribafalse.
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);
}
}
Entonces en mi Actividad ...
public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {
private ActionBarDrawerToggle mDrawerToggle;
public void showDrawerToggle(boolean showDrawerIndicator) {
mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-05 01:20:42
Esta respuesta estaba funcionando, pero había un pequeño problema con ella.
El getSupportActionBar().setDisplayHomeAsUpEnabled(false)
no se llamó explícitamente y estaba causando que el icono del cajón se ocultara incluso cuando no había elementos en el backstack, por lo que cambiar el método setActionBarArrowDependingOnFragmentsBackStack()
funcionó para mí.
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);
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:27
La lógica es clara. Mostrar botón atrás si la pila de fragmentos atrás está despejada. Mostrar animación de hamburguesa de material si la pila de fragmentos no está clara.
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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-07 12:58:25
Si echas un vistazo a la aplicación de GMAIL y vienes aquí a buscar el icono carret/affordance..
Les pediría que hicieran esto, ninguna de las respuestas anteriores fue clara. pude modificar la respuesta aceptada.
-
NavigationDrawer contains> Listview contiene subfragmentos.
-
Los subfragmentos se listarán así
FirstFragment = = posición 0 - - - > esto tendrá subfragmentos > > fragmento
- secondFragment
- Tercer fragmento y así sucesivamente....
En firstFragment tienes otro fragmento.
Llame a esto en DrawerActivity
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
mDrawerToggle.setDrawerIndicatorEnabled(false);
} else {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
});
Y en fragmento
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;
}
En el método de actividad del cajón onBackPressed establezca el interruptor del cajón en true para habilitar nuevamente el icono de la lista de navegación.
Gracias, Pusp
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-10 03:35:28
¡ Puedes ver este pequeño ejemplo! https://github.com/oskarko/NavDrawerExample
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-26 15:56:21
IMO, usando onNavigateUp() (como se muestra aquí) en la solución de riwnodennyk o Tom es más limpio y parece funcionar mejor. Simplemente reemplace el código onoptisitemseleccionado con esto:
@Override
public boolean onSupportNavigateUp() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// handle up navigation
return true;
} else {
return super.onSupportNavigateUp();
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:05