studio - navigation drawer android
Alternar entre la imagen de Android Navigation Drawer y Up caret cuando se utilizan fragmentos (12)
Al usar el Cajón de navegación, los desarrolladores de Android recomiendan que en ActionBar "solo las pantallas representadas en el Cajón de navegación deberían tener la imagen del Cajón de navegación" y que "todas las demás pantallas tengan el quilate tradicional".
Mira 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 en todos los niveles.
Al crear fragmentos de nivel inferior, puedo llamar a ActionBarDrawerToggle
setDrawerIndicatorEnabled(false)
para ocultar la imagen del Cajón de navegación y mostrar el cursor Up
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 tengo es cuando vuelvo a los fragmentos de nivel superior que aún muestra el quilate hacia arriba en lugar de la imagen original del cajón de navegación. ¿Alguna sugerencia sobre cómo "actualizar" la Barra de acciones en los fragmentos de nivel superior para volver a mostrar la imagen del Cajón de navegación?
Solución
La sugerencia de Tom funcionó para mí. Esto es lo que hice:
Actividad principal
Esta actividad controla todos los fragmentos en la aplicación.
Al preparar nuevos fragmentos para reemplazar a otros, configuré el DrawerToggle setDrawerIndicatorEnabled(false)
esta 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
, onBackPressed
lo anterior configurando el DrawerToggle para setDrawerIndicatorEnabled(true)
como este:
@Override
public void onBackPressed() {
super.onBackPressed();
// turn on the Navigation Drawer image;
// this is called in the LowerLevelFragments
setDrawerIndicatorEnabled(true)
}
En los LowerLevelFragments
En los fragmentos modifiqué onCreate
y onOptionsItemSelected
como este:
En onCreate
agregó setHasOptionsMenu(true)
para habilitar la configuración del menú de opciones. También configure setDisplayHomeAsUpEnabled(true)
para habilitar el < en la barra de acciones:
@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
siempre que se presione <, se llama a onBackPressed()
desde la actividad para subir un nivel en la jerarquía y visualizar 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;
…
}
¡Puedes mirar este pequeño ejemplo! https://github.com/oskarko/NavDrawerExample
Creé una interfaz para la actividad de alojamiento para actualizar el estado de vista del menú de hamburguesas. Para los fragmentos de nivel superior establezco el alternar en true
y para los fragmentos para los que quiero mostrar el up <arrow establecí el alternar en 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);
}
}
Entonces en mi actividad ...
public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {
private ActionBarDrawerToggle mDrawerToggle;
public void showDrawerToggle(boolean showDrawerIndicator) {
mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator);
}
}
Es fácil como 1-2-3.
Si quieres lograr:
1) Indicador de cajón : cuando no hay fragmentos en la pila posterior o se abre el cajón
2) Flecha : cuando algunos Fragmentos están en la Pila de Atrás
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);
}
}
PD Vea Crear un Cajón de navegación en Desarrolladores de Android en otros consejos sobre el comportamiento del indicador de 3 líneas.
Esta answer estaba funcionando, pero había un pequeño problema con ella. El getSupportActionBar().setDisplayHomeAsUpEnabled(false)
no fue llamado explícitamente y estaba causando que el ícono del cajón se ocultara incluso cuando no había elementos en el backstack, así 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);
}
}
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);
}
}
});
IMO, usando onNavigateUp () (como se muestra here ) en riwnodennyk''s o la solución de Tom es más limpia y parece funcionar mejor. Simplemente reemplace el código onOptionsItemSelected con esto:
@Override
public boolean onSupportNavigateUp() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// handle up navigation
return true;
} else {
return super.onSupportNavigateUp();
}
}
Intente manejar la selección de elementos de inicio en MainActivity dependiendo del estado de DrawerToggle. De esta forma, no tiene que agregar 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);
}
}
La lógica es clara. Mostrar el botón Atrás si la pila de fragmentos está clara. Muestre material de animación de devolución de hamburguesas 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;
}
Si echas un vistazo a la aplicación GMAIL y vienes aquí para buscar el icono de carret / affordance ...
Te pediría que hicieras esto, ninguna de las respuestas anteriores estaba clara. Pude modificar la respuesta aceptada.
NavigationDrawer -> Listview contiene subfragmentos.
los subfragmentos se enumerarán de esta manera
firstFragment == position 0 ---> esto tendrá subfragmentos -> fragment
- segundoFragmento
- ThirdFragment y demás ...
En firstFragment tienes otro fragmento.
Llamar 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 OnBackPressed Drawer, establezca el alternador del cajón en true para habilitar nuevamente el ícono de la lista de navegación.
Gracias, Pusp
Si el botón de la barra de acción no funciona, no olvide 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 cajones con un botón de inicio, todo funcionó excepto el botón de acción.
Usted ha escrito que, para implementar fragmentos de menor nivel, está reemplazando el fragmento existente, en lugar de implementar el fragmento de nivel inferior en una nueva actividad.
Creo que tendrías que implementar la funcionalidad de respaldo manualmente: cuando el usuario presionó hacia atrás tienes un código que muestra la pila (por ejemplo, en Activity::onBackPressed
override). Entonces, donde sea que hagas eso, puedes invertir el setDrawerIndicatorEnabled
.
SEGUIR
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 la pila está vacía.
@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 cursor de arriba para onOptionsItemSelected
.
En una de mis aplicaciones también necesitaba controlar el comportamiento de la herramienta de intercalación cuando presioné el botón Atrás. Esto se puede manejar anulando 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 executePendingTransactions
dos veces más executePendingTransactions
que en mi caso era necesario o de lo contrario a veces tuve comportamientos extraños del up caret.