Полнодиапазонный навигационный ящик
Я бы хотел создать полноразмерный навигационный ящик. Установка layout_width
в match_parent
на @+id/left_drawer
дает ширину около 80% пространства экрана. Это похоже на стандартное поведение. Нужно ли переопределять onMeasure()
из DrawerLayout
?
Мой текущий код:
<?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>
Спасибо.
Ответы
Ответ 1
Да, вы должны расширить DrawerLayout и переопределить некоторые методы, потому что MIN_DRAWER_MARGIN
есть private
Вот возможное решение:
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 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);
}
}
Ответ 2
Если вы хотите более простое решение, вы можете просто установить отрицательный запас
android:layout_marginLeft="-64dp"
для вашего 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"/>
Ответ 3
Поскольку все эти ответы не работали в ОС 6.0.1, я опубликую здесь решение, которое сработало для меня в сочетании с DrawerLayout
+ NavigationView
.
Итак, все, что я делаю, меняет ширину NavigationView
программно:
NavigationView 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);
Это работает для всех размеров экрана.
Ответ 4
На основе Robert Answer вы можете использовать layout_marginLeft=-64dp
для решения этой проблемы легко.
Однако он больше не работает на Android 5.0 и выше. Итак, вот мое решение, которое сработало для меня.
<?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>
В принципе, он добавляет правый край -64dp к корню DrawerLayout
, поэтому весь макет будет идти вправо для 64dp. И затем я добавляю layout_marginRight=64dp
в контент, чтобы он возвращался к исходной позиции. Тогда у вас может быть полный ящик.
Ответ 5
Вариант на решении Грогоры:
Вместо подкласса я вызываю следующий метод утилиты сразу после того, как я возьму ссылку на макет ящика:
/**
* 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();
}
}
Ответ 6
Nipper FullDrawerLayout Class просто просто потрясающий. Его производительность также быстрее, чем ящик по умолчанию, как можно когда-либо, использовать его на устройствах с api, у которых нет view.getLayoutDirection();
(i'e: Class не работает на всех устройствах для пряников)
так что я сделал
заменил все
view.getLayoutDirection();
с приведенным ниже кодом
GravityCompat.getAbsoluteGravity(gravity,ViewCompat.getLayoutDirection(this));
У меня есть обновленная библиотека поддержки, которая также расширила fullDrawerlayout до вспомогательного навигационного ящика. Теперь он отлично работает с пряничными устройствами.
Ответ 7
Еще один возможный способ решения проблемы без чрезмерного превышения:
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);
}
}
}
Если в какой-то момент поддержка библиотеки обновляется, и mMinDrawerMargin больше не существует, вы получите проблему с исключением и исправлением, прежде чем публиковать следующее обновление.
Я не делал измерений, но полагаю, что не так много отражений влияет на производительность. Кроме того, он выполняется только для создания каждого представления.
PS
странно, почему DrawerLayout сделан настолько негибким (я имею в виду личный минимальный запас) в этот момент...
Ответ 8
mDrawerLayout = (DrawerLayout) view.findViewById(R.id.drawer_layout); mDrawerList = (ListView) view.findViewById(R.id.top_sectionlist);
int width = getResources().getDisplayMetrics().widthPixels/2;
DrawerLayout.LayoutParams params = (android.support.v4.widget.DrawerLayout.LayoutParams) mDrawerList.getLayoutParams();
params.width = width;
mDrawerList.setLayoutParams(params);
Ответ 9
Попробуйте, это сработало для меня:
<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"/>
Установите ширину включенного макета android:layout_width="320dp"
. Для устройств с разным размером экрана вы можете динамически устанавливать ширину этого включенного макета.
Ответ 10
Вы можете использовать это. Вдохновленный этим сообщением , я обновил его для 5-го издания. Потому что у него были проблемы с StatusBar в версиях 5 и более поздних версий.
вам нужно расширить DrawerLayout и переопределить некоторые методы, поскольку MIN_DRAWER_MARGIN является закрытым
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 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;
}
}
Ответ 11
вы можете сделать код ниже
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);
Ответ 12
<?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>
Ответ 13
<?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>
Это отлично работает для меня. Надежда помогает другим.
Ответ 14
Вы также можете посмотреть класс SlidingDrawer. Это устаревший класс, но, как говорится в документации, вы можете написать свою собственную реализацию на основе ее исходного кода.
Ответ 15
Google рекомендует иметь максимальную ширину 320 dip в соответствии с рекомендациями пользовательского интерфейса здесь.
Более того, ширина может быть задана с помощью указателя layout_width в элементе ListView left_drawer.