web-dev-qa-db-fra.com

Tiroir de navigation: réglé comme toujours ouvert sur les tablettes

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)

enter image description here

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?

56
Waza_Be

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);
    }
}
47
jiahao

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/

32
methodin

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.

14
CommonsWare

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.


Étape 1

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>



Étape 2

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.

Étape 2.1

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 que
private boolean isDrawerFixed;
et l'initialiser comme
isDrawerFixed = 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){}.

Étape 2.2

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.

output

6
Anees

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;
    }
4
mister_potato