web-dev-qa-db-fra.com

Tiroir de navigation pleine largeur

J'aimerais créer un tiroir de navigation sur toute la largeur. Régler layout_width sur match_parent sur @+id/left_drawer donne une largeur d'environ 80% de l'espace d'écran. Cela semble être le comportement standard. Dois-je remplacer onMeasure() of DrawerLayout?

Mon code actuel: 

<?xml version="1.0" encoding="utf-8"?>
<Android.support.v4.widget.DrawerLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <FrameLayout
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:background="@color/black"
        Android:id="@+id/mainFragmentContainer">
    </FrameLayout>

    <include
        Android:id="@+id/left_drawer"
        Android:orientation="vertical"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        layout="@layout/drawer"/>
</Android.support.v4.widget.DrawerLayout>

Merci.

32
Martin

Oui, vous devez étendre DrawerLayout et remplacer certaines méthodes car MIN_DRAWER_MARGIN est private

Voici une solution possible:

public class FullDrawerLayout extends DrawerLayout {

    private static final int MIN_DRAWER_MARGIN = 0; // dp

    public FullDrawerLayout(Context context) {
        super(context);
    }

    public FullDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FullDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalArgumentException(
                    "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
        }

        setMeasuredDimension(widthSize, heightSize);

        // Gravity value for each drawer we've seen. Only one of each permitted.
        int foundDrawers = 0;
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);

            if (child.getVisibility() == GONE) {
                continue;
            }

            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            if (isContentView(child)) {
                // Content views get measured at exactly the layout's size.
                final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
                        widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
                final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
                        heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
                child.measure(contentWidthSpec, contentHeightSpec);
            } else if (isDrawerView(child)) {
                final int childGravity =
                        getDrawerViewGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
                if ((foundDrawers & childGravity) != 0) {
                    throw new IllegalStateException("Child drawer has absolute gravity " +
                            gravityToString(childGravity) + " but this already has a " +
                            "drawer view along that Edge");
                }
                final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
                        MIN_DRAWER_MARGIN + lp.leftMargin + lp.rightMargin,
                        lp.width);
                final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
                        lp.topMargin + lp.bottomMargin,
                        lp.height);
                child.measure(drawerWidthSpec, drawerHeightSpec);
            } else {
                throw new IllegalStateException("Child " + child + " at index " + i +
                        " does not have a valid layout_gravity - must be Gravity.LEFT, " +
                        "Gravity.RIGHT or Gravity.NO_GRAVITY");
            }
        }
    }

    boolean isContentView(View child) {
        return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
    }

    boolean isDrawerView(View child) {
        final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
        final int absGravity = Gravity.getAbsoluteGravity(gravity,
                child.getLayoutDirection());
        return (absGravity & (Gravity.LEFT | Gravity.RIGHT)) != 0;
    }

    int getDrawerViewGravity(View drawerView) {
        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
        return Gravity.getAbsoluteGravity(gravity, drawerView.getLayoutDirection());
    }

    static String gravityToString(int gravity) {
        if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
            return "LEFT";
        }
        if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
            return "RIGHT";
        }
        return Integer.toHexString(gravity);
    }

}
29
Nipper

Si vous voulez une solution plus simple, vous pouvez simplement définir une marge négative

Android:layout_marginLeft="-64dp"

pour votre left_drawer:

<include
        Android:id="@+id/left_drawer"
        Android:orientation="vertical"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        layout="@layout/drawer"
        Android:layout_marginLeft="-64dp"/>
111
Robert

Étant donné que toutes ces réponses ne fonctionnaient pas sous OS 6.0.1, je vais publier ici la solution qui fonctionnait pour moi en combinaison avec DrawerLayout + NavigationView.

Donc, tout ce que je fais est de changer la largeur de la NavigationView par programme:

mNavigationView = (NavigationView) findViewById(R.id.nv_navigation);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) mNavigationView.getLayoutParams();
params.width = metrics.widthPixels;
mNavigationView.setLayoutParams(params);

Cela fonctionne pour toutes les tailles d'écran.

20
Aksiom

Basé sur le Réponse de Robert , vous pouvez utiliser le layout_marginLeft=-64dp pour résoudre ce problème facilement.

Cependant cela ne semble plus fonctionner sous Android 5.0 et supérieur. Alors voici ma solution qui a fonctionné pour moi.

<?xml version="1.0" encoding="utf-8"?>
<Android.support.v4.widget.DrawerLayout
    Android:id="@+id/drawer_layout"
    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:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_marginRight="-64dp"
    Android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/content"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_marginRight="64dp"/>

    <include
        Android:id="@+id/left_drawer"
        Android:orientation="vertical"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        layout="@layout/drawer"/>

</Android.support.v4.widget.DrawerLayout>

Fondamentalement, ajoutez Android:layout_marginRight="-64dp" à la racine DrawerLayout afin que toute la présentation passe à droite pour 64dp.

Ensuite, j'ajoute le layout_marginRight=64dp au contenu afin qu'il retourne à la position d'origine. Ensuite, vous pouvez avoir un tiroir complet là-bas.

10
gentra

Une variante de la solution de Grogory:

Au lieu de sous-classer, j'appelle la méthode d'utilitaire suivante juste après avoir saisi une référence à la disposition du tiroir:

/**
 * The specs tell that
 * <ol>
 * <li>Navigation Drawer should be at most 5*56dp wide on phones and 5*64dp wide on tablets.</li>
 * <li>Navigation Drawer should have right margin of 56dp on phones and 64dp on tablets.</li>
 * </ol>
 * yet the minimum margin is hardcoded to be 64dp instead of 56dp. This fixes it.
 */
public static void fixMinDrawerMargin(DrawerLayout drawerLayout) {
  try {
    Field f = DrawerLayout.class.getDeclaredField("mMinDrawerMargin");
    f.setAccessible(true);
    f.set(drawerLayout, 0);

    drawerLayout.requestLayout();
  } catch (Exception e) {
    e.printStackTrace();
  }
}
9
Eugen Pechanec

La classe FullDrawerLayout de Nipper est tout simplement géniale ... ses performances sont également plus rapides que celles du tiroir par défaut; vous ne pouvez pas l’utiliser sur des appareils avec une API qui n’ont pas view.getLayoutDirection (); (I'e: Class ne fonctionne pas sur tous les appareils Gingerbread)

donc ce que j'ai fait était 

remplacé tous

view.getLayoutDirection();

avec le code ci-dessous 

GravityCompat.getAbsoluteGravity(gravity,ViewCompat.getLayoutDirection(this));

Ma bibliothèque de support a été mise à jour au plus tard et le fullDrawerlayout a également été étendu au tiroir de navigation du support. Maintenant, cela fonctionne très bien les appareils Gingerbread 

4
Aman Satija

Essayez ceci a fonctionné pour moi:

<include
    Android:id="@+id/left_drawer"
    Android:orientation="vertical"
    Android:layout_width="320dp"
    Android:layout_height="match_parent"
    Android:layout_gravity="start"
    layout="@layout/drawer"/>

Définir la largeur de la disposition incluse Android:layout_width="320dp". Pour les appareils avec une taille d'écran différente, vous pouvez définir de manière dynamique la largeur de cette disposition incluse.

4
GOLDEE

Un autre moyen possible de résoudre le problème sans trop insister:

public class FullScreenDrawerLayout extends DrawerLayout {

... //List of constructors calling
... //super(...);
... //init();

/** Make DrawerLayout to take the whole screen. */
protected void init() {
    try {

        Field field = getClass().getSuperclass().getDeclaredField("mMinDrawerMargin");
        field.setAccessible(true);
        field.set(this, Integer.valueOf(0));

    } catch (Exception e) {
        throw new IllegalStateException("Android.support.v4.widget.DrawerLayout has changed and you have to fix this class.", e);
    }
}

}

Si, à un moment donné, la bibliothèque de support est mise à jour et que mMinDrawerMargin n'y est plus, vous obtiendrez une exception et pourrez résoudre le problème avant de publier votre prochaine mise à jour.

Je n'ai pas pris de mesures, mais supposons qu'il n'y ait pas beaucoup de réflexions qui affectent les performances. De plus, il n'exécute qu'une création de vue.

PS C'est étrange pourquoi DrawerLayout est si inflexible (je suis sur la marge minimale privée) à ce stade ...

4
GregoryK

Vous pouvez utiliser ceci. Inspiré par ce post , je me suis mis à jour pour la 5ème édition. Parce qu'il avait des problèmes avec StatusBar dans les versions 5 et ultérieures.

vous devez étendre DrawerLayout et remplacer certaines méthodes car MIN_DRAWER_MARGIN est privé

public class FullDrawerLayout extends DrawerLayout {

    private static final int MIN_DRAWER_MARGIN = 0; // dp

    public FullDrawerLayout(Context context) {
        super(context);
    }

    public FullDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FullDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
            throw new IllegalArgumentException(
                    "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
        }

        setMeasuredDimension(widthSize, heightSize);

        //for support Android 5+
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Lollipop) {
            FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
            params.topMargin = getStatusBarHeight();
            setLayoutParams(params);
        }

        // Gravity value for each drawer we've seen. Only one of each permitted.
        int foundDrawers = 0;
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = getChildAt(i);

            if (child.getVisibility() == GONE) {
                continue;
            }

            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            if (isContentView(child)) {
                // Content views get measured at exactly the layout's size.
                final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
                        widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
                final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
                        heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
                child.measure(contentWidthSpec, contentHeightSpec);
            } else if (isDrawerView(child)) {
                final int childGravity =
                        getDrawerViewGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
                if ((foundDrawers & childGravity) != 0) {
                    throw new IllegalStateException("Child drawer has absolute gravity " +
                            gravityToString(childGravity) + " but this already has a " +
                            "drawer view along that Edge");
                }
                final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
                        MIN_DRAWER_MARGIN + lp.leftMargin + lp.rightMargin,
                        lp.width);
                final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
                        lp.topMargin + lp.bottomMargin,
                        lp.height);
                child.measure(drawerWidthSpec, drawerHeightSpec);
            } else {
                throw new IllegalStateException("Child " + child + " at index " + i +
                        " does not have a valid layout_gravity - must be Gravity.LEFT, " +
                        "Gravity.RIGHT or Gravity.NO_GRAVITY");
            }
        }
    }

    boolean isContentView(View child) {
        return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
    }

    boolean isDrawerView(View child) {
        final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
        final int absGravity = Gravity.getAbsoluteGravity(gravity,
                child.getLayoutDirection());
        return (absGravity & (Gravity.LEFT | Gravity.RIGHT)) != 0;
    }

    int getDrawerViewGravity(View drawerView) {
        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
        return Gravity.getAbsoluteGravity(gravity, drawerView.getLayoutDirection());
    }

    static String gravityToString(int gravity) {
        if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
            return "LEFT";
        }
        if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
            return "RIGHT";
        }
        return Integer.toHexString(gravity);
    }


    public int getStatusBarHeight() {
        int result = 0;
        int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "Android");
        if (resourceId > 0) {
            result = getResources().getDimensionPixelSize(resourceId);
        }
        return result;
    }

}
3
Rasoul Miri
<?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">

    <FrameLayout
        Android:id="@+id/container"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">

        <include
            layout="@layout/app_bar_dashboard"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent" />
    </FrameLayout>


    <Android.support.design.widget.NavigationView
        Android:id="@+id/nav_view"
        Android:layout_width="match_parent"
        Android:layout_marginRight="32dp"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        Android:fitsSystemWindows="true">

        <include layout="@layout/view_navigation_menu" />

    </Android.support.design.widget.NavigationView>

</Android.support.v4.widget.DrawerLayout>

Cela fonctionne parfaitement pour moi. J'espère aider les autres.

1
Jamariya R

vous pouvez par code ci-dessous 

 int width = getResources().getDisplayMetrics().widthPixels/2;
        DrawerLayout.LayoutParams params = (Android.support.v4.widget.DrawerLayout.LayoutParams) drawer_Linear_layout.getLayoutParams();
        params.width = width;
        drawer_Linear_layout.setLayoutParams(params);
1
Kirtikumar A.
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical"
tools:context=".UserListActivity">

<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_alignParentTop="true"
    Android:background="@drawable/common_gradient"
    Android:layoutDirection="rtl"
    Android:orientation="vertical">

    <RelativeLayout
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        Android:layout_weight="0.2">

        <TextView
            Android:id="@+id/userType_textView"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_centerHorizontal="true"
            Android:layout_centerVertical="true"
            Android:text="نوع المستخدم"
            Android:textColor="#000000"
            Android:textSize="20sp"
            tools:text="نوع المستخدم" />

        <TextView
            Android:id="@+id/className_textView"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_below="@+id/userType_textView"
            Android:layout_centerHorizontal="true"
            Android:text="إسم القسم"
            Android:textColor="#000000"
            Android:textSize="16sp"
            tools:text="إسم القسم" />

        <ImageButton
            Android:layout_width="30dp"
            Android:layout_height="20dp"
            Android:layout_alignBottom="@+id/userType_textView"
            Android:layout_marginLeft="15dp"
            Android:layout_marginStart="15dp"
            Android:background="@Android:color/transparent"
            Android:contentDescription="@string/desc"
            Android:onClick="showMenuAction"
            Android:scaleType="fitCenter"
            Android:src="@drawable/menu" />
    </RelativeLayout>

    <RelativeLayout
        Android:layout_width="match_parent"
        Android:layout_height="0dp"
        Android:layout_weight="0.8"

        Android:background="#FAFAFA">

        <SearchView
            Android:id="@+id/user_searchView"
            Android:layout_width="match_parent"
            Android:layout_height="45dp"
            Android:layout_alignParentTop="true"
            Android:layout_centerHorizontal="true"
            Android:background="#9CC3D7" />

        <ListView
            Android:id="@+id/users_listView"
            Android:layout_width="100dp"
            Android:layout_height="100dp"

            Android:layout_alignParentBottom="true"
            Android:layout_below="@+id/user_searchView"
            Android:layout_centerHorizontal="true"
            Android:divider="#DFDEE1"
            Android:dividerHeight="1dp" />
    </RelativeLayout>

</LinearLayout>

<Android.support.v4.widget.DrawerLayout
    Android:id="@+id/navigationDrawerUser"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"

    Android:layoutDirection="rtl">


    <ExpandableListView
        Android:id="@+id/menu_listView_user"
        Android:layout_width="240dp"
        Android:layout_height="match_parent"
        Android:layout_gravity="start"
        Android:background="#195269"
        Android:choiceMode="singleChoice"
        Android:divider="#2C637D"
        Android:dividerHeight="1dp"
        Android:groupIndicator="@null">

    </ExpandableListView>

</Android.support.v4.widget.DrawerLayout>

0
khawlouta