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

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.

 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/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.

 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/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);
                }
            }
        });
 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/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.

 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/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);
    }
}
 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/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.

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

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

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

 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/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

 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/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();
    }
}
 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:03:05