android - studio - Diseño de materiales: ancho del cajón de navegación
material design android studio (6)
De acuerdo con las especificaciones de Material Design, el ancho del Nav Drawer en los dispositivos móviles debe ser
ancho de navegación lateral = ancho de la pantalla - altura de la barra de la aplicación
¿Cómo implementamos esto en Android?
Tengo dos soluciones parciales. Primero es el camino hacky: en la actividad que contiene pongo este código:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR1) { final Display display = getWindowManager().getDefaultDisplay(); final Point size = new Point(); display.getSize(size); final ViewGroup.LayoutParams params = mDrawerFragment.getView().getLayoutParams(); params.width = size.x - getResources().getDimensionPixelSize( R.dimen.abc_action_bar_default_height_material ); mFragmentUserList.getView().setLayoutParams(params); }
Esto, sin embargo, causa un segundo ciclo de disposición y no funciona en gingerbread: no es óptimo.
La segunda solución implica agregar un espacio entre el fragmento y el cajónDisposición. Sin embargo, desplaza la sombra y el lugar donde el usuario puede presionar para regresar a la aplicación principal. También se bloquea cuando se presiona el ícono "hamburguer". No es óptimo tampoco.
¿Hay una mejor solución, preferiblemente una que involucre estilos y xml?
Bueno, esto me pareció muy difícil de comprender e implementar. Desafortunadamente, la solución de Matthew hizo que mi cajón de navegación fuera demasiado ancho para el paisaje, y parecía contrario a las prácticas de Google, es decir, el ancho de navegación está determinado por el ancho más pequeño del dispositivo. En cualquier caso, no funcionaría en mi caso ya que desactivé la configuración en mi manifiesto. Así que decidí cambiar el ancho de navegación dinámicamente con el siguiente código.
Cabe señalar que mi aplicación es solo para teléfonos y decidí que 320dp es el ancho máximo. Esta es también la razón por la que me he decidido por la altura de la barra de herramientas de 56dp para ambas orientaciones.
Espero que ayude a alguien, y que puedan evitar el estrés innecesario que me causó.
navDrawLayout.post(new Runnable()
{
@Override
public void run() {
Resources r = getResources();
DisplayMetrics metrics = new DisplayMetrics();
if(r.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int height = metrics.heightPixels;
float screenWidth = height / r.getDisplayMetrics().density;
float navWidth = (screenWidth - 56);
navWidth = Math.min(navWidth, 320);
int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics());
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams();
params.width = newWidth;
navDrawLayout.setLayoutParams(params);
}
if(r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
getWindowManager().getDefaultDisplay().getMetrics(metrics);
int width = metrics.widthPixels;
float screenWidth = width / r.getDisplayMetrics().density;
float navWidth = screenWidth - 56;
navWidth = Math.min(navWidth, 320);
int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics());
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams();
params.width = newWidth;
navDrawLayout.setLayoutParams(params);
}
}
}
);
Con la Biblioteca de soporte de diseño de Android , ahora es realmente sencillo implementar un cajón de navegación que incluye el tamaño correcto. Use NavigationView y use su capacidad para hacer que el cajón salga del recurso del menú (ejemplo aquí ) o simplemente puede envolverlo alrededor de la vista que usa actualmente para mostrar su lista de cajones (por ejemplo, ListView, RecyclerView). NavigationView se encargará del tamaño del cajón para usted.
Aquí hay un ejemplo de cómo uso NavigationView en ListView:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/navdrawer_layout"
android:fitsSystemWindows="true">
<!-- Layout where content is shown -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include android:id="@+id/toolbar"
layout="@layout/toolbar" />
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar" />
<!-- Toolbar shadow for pre-lollipop -->
<View style="@style/ToolbarDropshadow"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_below="@id/toolbar" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start">
<ListView
android:id="@+id/navdrawer_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:choiceMode="singleChoice"
android:dividerHeight="0dp"
android:divider="@null"/>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
De esta manera puede usar el dimensionamiento de NavigationViews y aún usar su propia lista de cajones. Aunque es mucho más fácil hacer que la lista de cajones salga del recurso de menú (ejemplo aquí ), no puede usar vistas personalizadas para los elementos de la lista.
Después de buscar una solución más simple, encontré un artículo muy claro: tamaño del cajón de navegación de materiales .
Aquí:
La pantalla del Nexus 5 es de 640 x 360 dp (xxhdpi), y una barra de la aplicación tiene una altura de 56 dp. Entonces el cajón de navegación debería ser:
[ancho en dp] = 360dp - 56dp = 304dp
En su lugar, un Nexus 4 tiene una pantalla de 640 x 384 dp (xhdpi). La misma altura de la barra de aplicaciones de 56dp. ¿Su cajón de navegación?
[ancho en dp] = 384dp - 56dp = 328dp
Entonces, ¿cómo llegaron los diseñadores de Google con 288dp y 304dp de ancho, respectivamente? No tengo idea.
Las aplicaciones de Google, por otro lado, parecen estar de acuerdo con mis matemáticas. Ah, ¿y sabes qué es lo más divertido en todo esto? El iPhone (que tiene diferentes alturas de pantalla, pero un ancho constante de 320 dp) está marcado correctamente como tener un cajón de navegación de 264dp.
Básicamente, muestra que algunas pautas sobre el cajón de navegación se contradicen y que puede usar la siguiente regla para evitar cálculos:
Básicamente, puede usar siempre 304dp en -sw360dp y 320dp en -sw384dp para su cajón de navegación, y lo hará bien.
El ancho del Cajón de navegación depende del ancho, la orientación y la versión de Android más pequeños del dispositivo.
Echa un vistazo a este artículo sobre el dimensionamiento de Navigation Drawer.
Logré hacer una solución usando declaraciones de estilo XML, pero también es un poco hacky. Mi enfoque fue utilizar los márgenes en lugar de aplicar un ancho establecido para evitar escribir cualquier código para calcular el diseño de forma manual. Creé una regla de estilo básica para resaltar cómo hacer que funcione.
Desafortunadamente, DrawerLayout actualmente aplica un margen mínimo de 64dp. Para que este enfoque funcione, necesitamos compensar ese valor con márgenes negativos para que podamos obtener el ancho deseado para el cajón de navegación. Esperemos que esto pueda resolverse en el futuro ( alguien ha archivado un problema al respecto ) por lo que solo podemos hacer referencia a la referencia de dimensión abc_action_bar_default_height_material
para el margen.
Sigue estos pasos:
Agregue las siguientes definiciones de dimensión y estilo:
valores / dimens.xml
<!-- Match 56dp default ActionBar height on portrait orientation --> <dimen name="nav_drawer_margin_offset">-8dp</dimen>
values-land / dimens.xml
<!-- Match 48dp default ActionBar height on landscape orientation --> <dimen name="nav_drawer_margin_offset">-16dp</dimen>
valores / styles.xml
<!-- Nav drawer style to set width specified by Material Design specification --> <style name="NavDrawer"> <item name="android:layout_width">match_parent</item> <item name="android:layout_marginRight">@dimen/nav_drawer_margin_offset</item> </style>
values-sw600dp / styles.xml
<!-- Margin already matches ActionBar height on tablets, just modify width --> <style name="NavDrawer"> <item name="android:layout_width">320dp</item> <item name="android:layout_marginRight">0dp</item> </style>
Una vez que haya agregado las reglas anteriores en su proyecto, puede hacer referencia al estilo de NavDrawer en la vista del panel de navegación:
layout / navigation_drawer.xml (u otra vista apropiada que se utiliza para su cajón de navegación)
<?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/navigation_drawer" style="@style/NavDrawer" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="singleChoice" android:divider="@android:color/transparent" android:dividerHeight="0dp" android:background="#FFF" />
Ya actualizaron las especificaciones, ahora el ancho del cajón de navegación es:
Math.min(screenWidth — actionBarSize, 6 * actionBarSize);