这种情况是否可能使用当前实现呢,还是我们必须创建一个新的布局和一个包含ListView的新结构,而不是重用同一份代码?
基于大型设备可以有不同的布局文件的想法,我创建了以下项目。
https://github.com/jiahaoliuliu/ABSherlockSlides
亮点:
由于大型设备的抽屉始终可见,因此无需具有抽屉。相反,一个带有两个相同名称元素的LinearLayout就足够了。
<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>
因为在布局文件中没有抽屉,当应用程序尝试在布局中查找元素时,它将返回 null。因此,没有必要使用额外的布尔变量来查看使用哪个布局。
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);
}
这里是将其用作布尔值的示例。
@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);
}
}
在CommonsWare的回答基础上,您可以通过进行几个调整来实现这一点。第一个是设置以下三行:
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值,它将是DrawerLayout的宽度。
这使您可以检查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;
}
你可以将所有不想启用的功能都包含在一个 if(!isDrawerLocked)
语句中。这将包括:
drawerLayout.setDrawerListener(drawerToggle);
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"/>
这里的美妙之处在于您可以通过为要针对的设备设置备用dimen.xml文件来控制所有逻辑,并且您唯一需要更改的是drawerContentPadding的值并提供修改过的布局。
注意: 我最终使用margin_left而不是padding_left,因为在新布局中它会覆盖抽屉。有关该技术的更深入的博客文章,请参见http://derekrwoods.com/2013/09/creating-a-static-navigation-drawer-in-android/
尝试使用setDrawerLockMode()
来锁定大屏设备上的抽屉打开。
正如我在评论中所指出的那样,我认为DrawerLayout
并不适用于您的场景(虽然我认为这不是一个坏主意)。要么使用一个承载相同ListView
和内容的不同布局,或者可能下载并修改自己的DrawerLayout
,在大屏设备上打开时将内容滑动而不是重叠。
DrawerLayout
并不适合你的情况。要么使用一个不同的布局来承载相同的ListView
和内容,要么下载并修改自己的DrawerLayout
副本,在大屏幕设备上打开时将内容滑动而不是重叠。 - CommonsWare为平板电脑提供一个备用的布局文件。这样,您可以保存 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>
在这一步中,我们将进行足够的更改,以确保抽屉的打开和关闭仅适用于非平板设备。
将以下内容添加到值目录中的新值资源文件中,并将其命名为config_ui.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isDrawerFixed">false</bool>
</resources>
这是针对非平板设备的。对于平板设备,请创建另一个同名文件并将其放置在values-w600dp-land
中。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="isDrawerFixed">true</bool>
</resources>
private boolean isDrawerFixed;
并将其初始化为
isDrawerFixed = getResources().getBoolean(R.bool.isDrawerFixed);
。if (isDrawerFixed){}
。if
语句包装设置操作栏上切换按钮的代码。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
语句包装在一起,如下所示。
if (!isDrawerFixed) {
drawer.closeDrawer(GravityCompat.START);
}
RelativeLayout
,而不是 LinearLayout
,我不能只使用 LinearLayout
来显示主/详细片段。再次感谢您。额外加分,因为您提供了截图作为证据,并与我的设备进行了比较。 - Sakiboy之前的回答都很好,但是在我的项目中实现时遇到了一些问题,所以我想分享我的解决方案。 首先,我们需要定义一个自定义抽屉:
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>
在纵向方向上,NavigationView的内容填充为0dp,在横向方向上大约为300dp(通过经验确定)。我们在适当的values
文件夹中定义它们:
values/dimens.xml
-
<dimen name="content_padding">0dp</dimen>
values-land/dimens.xml
-
<dimen name="content_padding">300dp</dimen>
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;
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_navdrawer"
app:menu="@menu/activity_main_drawer" />
<include
android:id="@+id/app_bar_navdrawer"
layout="@layout/app_bar_navdrawer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</androidx.drawerlayout.widget.DrawerLayout>
res/layout-sw600dp-land
就足够了吗? - Alexander Farber