J'utilise le modèle de tiroir de navigation de la bibliothèque de support technique: http://developer.Android.com/training/implementing-navigation/nav-drawer.html
J'essayais de le configurer comme toujours ouvert sur la tablette (comme menu latéral)
Est-ce possible avec l'implémentation actuelle ou devons-nous créer une nouvelle mise en page et une nouvelle structure avec une vue en liste au lieu de réutiliser le même code?
Sur la base de l'idée que de plus gros périphériques pourraient avoir des fichiers de disposition différents, j'ai créé le projet suivant.
https://github.com/jiahaoliuliu/ABSherlockSlides
HighLights :
Étant donné que le tiroir d'un grand appareil est toujours visible, il n'est pas nécessaire de disposer d'un tiroir. Au lieu de cela, un LinearLayout avec deux éléments du même nom suffira.
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="horizontal">
<ListView
Android:id="@+id/listview_drawer"
Android:layout_width="@dimen/drawer_size"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:choiceMode="singleChoice"
Android:divider="@Android:color/transparent"
Android:dividerHeight="0dp"
Android:background="@color/drawer_background"/>
<FrameLayout
Android:id="@+id/content_frame"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_marginLeft="@dimen/drawer_content_padding"
/>
</LinearLayout>
Parce que nous n'avons pas le tiroir dans le fichier de mise en page, lorsque l'application essaie de trouver l'élément dans la mise en page, elle renvoie la valeur null. Il n’est donc pas nécessaire d’avoir un booléen supplémentaire pour voir quelle disposition utilise.
DrawerLayout mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
if (mDrawerLayout != null) {
// Set a custom shadow that overlays the main content when the drawer opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
// Enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// ActionBarDrawerToggle ties together the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_drawer,
R.string.drawer_open,
R.string.drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
public void onDrawerOpened(View drawerView) {
// Set the title on the action when drawer open
getSupportActionBar().setTitle(mDrawerTitle);
super.onDrawerOpened(drawerView);
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
Voici l'exemple pour l'utiliser comme booléen.
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if (mDrawerLayout != null) {
mDrawerToggle.syncState();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mDrawerLayout != null) {
// Pass any configuration change to the drawer toggles
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
En vous appuyant sur la réponse de CommonsWare, vous pouvez le faire avec quelques ajustements. La première consiste à définir les trois lignes suivantes:
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
isDrawerLocked = true;
La couleur de tiroirNoShadow peut simplement être une couleur non alpha (comme 0x00000000). Cela vous donne un tiroir ouvert sans superposition d'arrière-plan.
La deuxième chose à faire est d’ajuster la valeur padding_left de votre FrameLayout. À cette fin, vous pouvez configurer une dimension pour contrôler cela (0dp par défaut) - dans cet exemple, R.dimen.drawerContentPadding. Vous aurez également besoin d'une valeur R.dimen.drawerSize qui sera la largeur de DrawerLayout.
Cela vous permet de vérifier la valeur paddingLeft de FrameLayout pour appeler ces lignes.
FrameLayout frameLayout = (FrameLayout)findViewById(R.id.content_frame);
if(frameLayout.getPaddingLeft() == (int)getResources().getDimension(R.dimen.drawerSize) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
isDrawerLocked = true;
}
Vous pouvez ensuite envelopper toutes les fonctionnalités que vous ne voulez pas activer dans une instruction if(!isDrawerLocked)
. Cela comprendra:
drawerLayout.setDrawerListener(drawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
Enfin, vous devez configurer des présentations alternatives pour les vues avec un tiroir statique. Un exemple est:
<FrameLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v4.widget.DrawerLayout
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<!-- The navigation drawer -->
<ListView
Android:id="@+id/left_drawer"
Android:layout_width="@dimen/drawerSize"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:choiceMode="singleChoice"
Android:divider="@Android:color/transparent"
Android:dividerHeight="0dp"
Android:background="#111"/>
</Android.support.v4.widget.DrawerLayout>
<FrameLayout
Android:id="@+id/content_frame"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_marginLeft="@dimen/drawerContentPadding"/>
La beauté ici est que vous pouvez alors contrôler toute la logique en configurant d’autres fichiers dimen.xml pour les périphériques que vous souhaitez cibler. La seule chose à modifier est la valeur de drawContentPadding et l’offre des présentations modifiées.
REMARQUE: J'ai fini par utiliser margin_left au lieu de padding_left car, dans la nouvelle présentation, ce dernier recouvre le tiroir. Voir un article de blog plus détaillé sur la technique à l'adresse http://derekrwoods.com/2013/09/creating-a-static-navigation-drawer-in-Android/
Essayez setDrawerLockMode()
pour verrouiller le tiroir en position ouverte sur les appareils à grand écran.
Comme je l'ai noté dans un commentaire, je ne pense pas que DrawerLayout
soit conçu pour votre scénario (bien que ce ne soit pas une mauvaise idée, à mon humble avis). Utilisez une présentation différente qui héberge les mêmes ListView
et le même contenu, ou téléchargez et modifiez vous-même votre copie de DrawerLayout
qui, sur les appareils à grand écran, fait glisser le contenu à la position ouverte plutôt que de se chevaucher il.
Fournissez simplement un autre fichier de mise en page pour les tablettes. De cette façon, vous pouvez enregistrer tous les comportements par défaut de NavigationView
.
Créez simplement un autre fichier de présentation similaire à celui-ci pour les tablettes et placez-le dans le répertoire de ressources layout-w600dp-land
.
<?xml version="1.0" encoding="utf-8"?>
<Android.support.v4.widget.DrawerLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:openDrawer="start">
<!--
NavigationView and the content is placed in a horizontal LinearLayout
rather than as the direct children of DrawerLayout.
This makes the NavigationView always visible.
-->
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="horizontal">
<Android.support.design.widget.NavigationView
Android:id="@+id/nav"
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"/>
<include
layout="@layout/app_bar_main"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</LinearLayout>
</Android.support.v4.widget.DrawerLayout>
Au cours de cette étape, nous apporterons suffisamment de modifications pour nous assurer que l'ouverture et la fermeture du tiroir ne fonctionnent que sur des périphériques autres que des tablettes.
Ajoutez le contenu suivant à un nouveau fichier de ressources de valeur dans le répertoire values et nommez-le config_ui.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isDrawerFixed">false</bool>
</resources>
C'était pour les appareils non-tablettes. Pour les tablettes, créez-en une autre portant le même nom et placez-la dans values-w600dp-land
.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isDrawerFixed">true</bool>
</resources>
Créer un nouveau champ dans la classe de l'activité à laquelle appartient le tiroir en tant queprivate boolean isDrawerFixed;
et l'initialiser commeisDrawerFixed = getResources().getBoolean(R.bool.isDrawerFixed);
.
Nous pouvons maintenant vérifier si le périphérique est un tabled ou un non-tablette aussi simple que if (isDrawerFixed){}
.
Enveloppez le code qui configure le bouton bascule sur la barre d’action avec une instruction if
comme celle-ci.
if (!isDrawerFixed) {
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
}
Enveloppez le code qui ferme le tiroir quand un élément est cliqué avec une autre instruction if
comme celle-ci.
if (!isDrawerFixed) {
drawer.closeDrawer(GravityCompat.START);
}
Le résultat final ressemblera un peu à ceci.
Les réponses précédentes sont bonnes, mais j'ai rencontré quelques problèmes lors de leur implémentation dans mon projet, je souhaite donc partager ma solution. Tout d’abord, nous devons définir un tiroir personnalisé:
public class MyDrawerLayout extends DrawerLayout {
private boolean m_disallowIntercept;
public MyDrawerLayout (Context context) {
super(context);
}
@Override
public boolean onInterceptTouchEvent(final MotionEvent ev) {
// as the drawer intercepts all touches when it is opened
// we need this to let the content beneath the drawer to be touchable
return !m_disallowIntercept && super.onInterceptTouchEvent(ev);
}
@Override
public void setDrawerLockMode(int lockMode) {
super.setDrawerLockMode(lockMode);
// if the drawer is locked, then disallow interception
m_disallowIntercept = (lockMode == LOCK_MODE_LOCKED_OPEN);
}
}
Ensuite, nous le plaçons dans une structure d'activité de base (sans dispositions arbitraires des réponses précédentes) comme ceci:
<MyDrawerLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:openDrawer="start">
<!--We must define left padding for content-->
<FrameLayout
Android:id="@+id/content_frame"
Android:paddingStart="@dimen/content_padding"
Android:layout_width="match_parent"
Android:layout_height="match_parent"/>
<Android.support.design.widget.NavigationView
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:fitsSystemWindows="true"
app:menu="@menu/menu_nav" />
</MyDrawerLayout>
Le remplissage de contenu ici est 0dp en orientation portrait et environ 300dp en paysage pour NavigationView (calculé de manière empirique). Nous les définissons dans les dossiers values
appropriés:
values/dimens.xml
-
<dimen name="content_padding">0dp</dimen>
values-land/dimens.xml
-
<dimen name="content_padding">300dp</dimen>
Enfin, nous verrouillons le tiroir dans l’activité:
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
mDrawerLayout.setScrimColor(0x00000000); // or Color.TRANSPARENT
isDrawerLocked = true;
} else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
mDrawerLayout.setScrimColor(0x99000000); // default shadow
isDrawerLocked = false;
}