Android 导航抽屉:在平板电脑上设置为始终打开
我正在使用支持库中的导航抽屉模式: 我试图将其设置为在平板电脑上始终打开(作为一个侧菜单) 在当前的实现中,这是可能的,还是我们必须使用Listview创建一个新的布局和新的结构,而不是重复使用相同的代码?在大屏幕设备上锁定打开的抽屉Android 导航抽屉:在平板电脑上设置为始终打开,android,tablet,navigation-drawer,Android,Tablet,Navigation Drawer,我正在使用支持库中的导航抽屉模式: 我试图将其设置为在平板电脑上始终打开(作为一个侧菜单) 在当前的实现中,这是可能的,还是我们必须使用Listview创建一个新的布局和新的结构,而不是重复使用相同的代码?在大屏幕设备上锁定打开的抽屉 正如我在评论中指出的,我不认为DrawerLayout是为您的场景设计的(尽管这不是一个坏主意,IMHO)。可以使用不同的布局来承载相同的列表视图和内容,也可以下载并修改您自己的抽屉布局,在大屏幕设备上,打开内容时将其滑动而不是重叠。根据Commonware的
正如我在评论中指出的,我不认为
DrawerLayout
是为您的场景设计的(尽管这不是一个坏主意,IMHO)。可以使用不同的布局来承载相同的列表视图
和内容,也可以下载并修改您自己的抽屉布局
,在大屏幕设备上,打开内容时将其滑动而不是重叠。根据Commonware的答案,您可以进行一些调整。第一个是设置以下三行:
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
isDrawerLocked = true;
drawerNoShadow颜色只能是无alpha颜色(如0x00000000)。这会让你有一个没有背景覆盖的开放抽屉
您需要做的第二件事是调整FrameLayout的padding_left值。为此,您可以设置一个维度来控制此操作(默认情况下为0dp)-在本例中为R.dimen.drawerContentPadding。您还需要一个R.dimen.drawerSize值,该值将是抽屉布局的宽度
这允许您检查FrameLayout的paddingLeft值以调用这些行
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;
}
然后,如果(!isDrawerLocked)语句中包含所有不希望启用的功能,则可以将其包装到语句中。这将包括:
drawerLayout.setDrawerListener(抽屉切换)代码>
getActionBar().setDisplayHomeAsUpEnabled(true)代码>
最后,您确实需要为具有静态抽屉的视图设置备用布局。例如:
<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"/>
基于大型设备可能有不同布局文件的想法,我创建了以下项目
突出显示:
由于大型设备的抽屉始终可见,因此不需要有抽屉。相反,具有两个同名元素的线性布局就足够了
<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>
下面是将其用作布尔值的示例
@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);
}
}
前面的答案很好,但是在我的项目中实现它们时我遇到了一些问题,所以我想分享我的解决方案。
首先,我们需要定义一个自定义抽屉:
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);
}
}
然后我们把它放在一个基本的活动布局中(没有前面答案中的任意布局),如下所示:
<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>
values land/dimens.xml
-
<dimen name="content_padding">0dp</dimen>
<dimen name="content_padding">300dp</dimen>
只需为平板电脑提供一个备用布局文件。这样,您就可以保存NavigationView
的所有默认行为
第一步
只需为平板电脑设备创建一个类似于此的备用布局文件,并将其放置在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>
这是针对非平板设备的。对于平板电脑设备,创建另一个同名设备,并将其放入values-w600dp-land
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isDrawerFixed">true</bool>
</resources>
使用下面的另一条if
语句包装当单击某个项目时关闭抽屉的代码
if (!isDrawerFixed) {
drawer.closeDrawer(GravityCompat.START);
}
最终结果将有点像这样
if (!isDrawerFixed) {
drawer.closeDrawer(GravityCompat.START);
}
抽屉打开了,但在我实际布局的前面。@wazau_-Be:哦,对了。我不认为DrawerLayout
是为您的场景设计的。可以使用不同的布局来承载相同的列表视图
和内容,也可以下载并修改您自己的抽屉布局
,在大屏幕设备上,打开时将内容滑动而不是重叠。我接受了您的答案,但如果您将您的评论复制到答案中,则会很有用;-)很好的例子!由于您将其更改为padding_left而不是margin,因此您无法再使用示例检测哪个布局。但是,如果您在每个版面上设置了一个标记,则可以比较该标记以查找正在使用的版面。***不过还有一件事——我发现在抽屉锁定在“out”位置后,当我切换回“Picture”以便打开/关闭时,滑动动作不再打开抽屉。知道为什么吗?我还刚刚意识到,在从打开的抽屉切换回肖像模式后,我的onKeyDown事件停止触发活动!我正在使用兼容性片段,我想知道其中是否有bug…我通过将此代码移到onpostreate()中解决了大部分问题,但是,如果你试图在抽屉被锁定打开的同时将其关闭,我仍然会崩溃。@methodin如果你能将完整的代码添加到你的博客中,我将不胜感激。@eddy如果你知道如何运行代码,如何确定它是平板设备?使用res/layout-sw600dp-land
是否足够?这是一个古老但有趣的问题。您可能会在这里找到答案:请注意,仅通过创建此文件夹并将布局放置在其中,并不意味着将使用此布局。如果需要,您可以检测它是否为平板电脑,然后通过编程强制它处于横向模式。这样就行了。祝你好运我认为这是目前为止最好的答案,因为没有重复的代码,它利用了NavigationView API为导航图让路。干得好。这是一个很好的答案。比其他提供的要容易和明智得多。非常感谢。我使用了RelativeLayout
而不是LinearLayout
,仅使用LinearLayout
无法显示主/细节片段。再次感谢。提供屏幕截图进行验证并与我的设备进行比较的额外要点。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isDrawerFixed">true</bool>
</resources>
if (!isDrawerFixed) {
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
}
if (!isDrawerFixed) {
drawer.closeDrawer(GravityCompat.START);
}