如何使用相同的 Z 将 View 与 DrawerLayout 内容一起移动
How move View alongside DrawerLayout's content whit the same Z
我的主视图在屏幕右上角的垂直 LinearLayout
中有 3 个 Button
s。每个按钮显示一些 Fragment
,这些 Fragment
位于 DrawerLayout
中。像这样:
当我单击任何按钮时,我希望 DrawerLayout 从右侧显示,并且此按钮与其一起翻译。像这样:
我已经设法将 Button
与抽屉一起移动,但我的问题是抽屉的阴影也会影响按钮。我希望它与抽屉的内容一样亮(相同高度),但我也希望其他按钮保留在抽屉后面。
这是我的activity_main.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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:fitsSystemWindows="true">
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/content_main"/>
<LinearLayout ... >
<ImageButton ... />
<ImageButton ... />
<ImageButton ... />
</LinearLayout>
<FrameLayout
android:id="@+id/fragment_secondary_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="right"
tools:context="..."/>
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
有了 DrawerLayout
内的按钮,抽屉移动到它们上方,但正在翻译的那个变暗了。
另一方面,如果我将按钮放在 DrawerLayout 之外,移动的按钮看起来没问题,但抽屉位于其他按钮下方。喜欢:
有什么办法可以避免DrawerLayout的阴影影响到特定的视图吗?或者也许取消它?
DrawerLayout
在其 drawChild()
方法中将阴影 - 稀松布 - 应用于其 child View
s。它通过检查给定的 child 不是抽屉 View
来确定将其应用于哪个 children。它最终通过检查 child 的 LayoutParams
的 gravity
来做到这一点。
知道这一点,我们可以创建一个自定义 DrawerLayout
subclass 来覆盖 drawChild()
,并临时更改 child 上的 gravity
我们不想应用稀松布。由于在绘制期间没有发生布局,因此这不会影响 View
.
的实际位置
public class CustomDrawerLayout extends DrawerLayout {
private int noScrimId;
public CustomDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// Get the ID for the no-scrim View.
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomDrawerLayout);
noScrimId = a.getResourceId(R.styleable.CustomDrawerLayout_noScrimView, View.NO_ID);
a.recycle();
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
// Is this the child we want?
final boolean isNoScrimView = child.getId() == noScrimId;
// If yes, temporarily tag it as a drawer.
if (isNoScrimView) {
((LayoutParams) child.getLayoutParams()).gravity = Gravity.LEFT;
}
// Let the super class do the draw, and save the return.
final boolean res = super.drawChild(canvas, child, drawingTime);
// Reset the gravity if we changed it.
if (isNoScrimView) {
((LayoutParams) child.getLayoutParams()).gravity = Gravity.NO_GRAVITY;
}
return res;
}
}
此示例使用自定义属性,以便可以在布局中指定 "no-scrim" View
。如果不想使用该属性,可以从构造函数中删除 TypedArray
处理,然后硬编码一个 ID。如果你确实想使用自定义属性,你需要在你的项目中定义它,你可以通过将以下文件粘贴到 values/
文件夹中,或者添加到可能已经存在的文件中来实现。
attrs.xml
<resources>
<declare-styleable name="CustomDrawerLayout">
<attr name="noScrimView" format="reference" />
</declare-styleable>
</resources>
CustomDrawerLayout
是 drop-in 的替代品,您可以像使用常规 class 一样在布局中使用它。例如,如果您的 ImageButton
的 LinearLayout
的 ID 为 button_menu
:
<com.mycompany.myapp.CustomDrawerLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:noScrimView="@+id/button_menu">
请注意,如果您碰巧将抽屉 View
设置为 noScrimView
,您会很不高兴的。此外,noScrimView
必须是 DrawerLayout
的直接 child,因为稀松布效果仅适用于那些。
为简单起见,我省略了示例中的任何检查,但如果您希望包括一些检查,请在 onMeasure()
方法中执行它们将符合 DrawerLayout
处理它的方式自己的支票。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final View v = findViewById(noScrimId);
if (v != null) {
if (!(v.getLayoutParams() instanceof LayoutParams)) {
throw new IllegalStateException("noScrimView must be a child of DrawerLayout");
}
if (((LayoutParams) v.getLayoutParams()).gravity != Gravity.NO_GRAVITY) {
throw new IllegalStateException("noScrimView cannot be a drawer View");
}
}
else {
if (noScrimId != View.NO_ID) {
Log.d(getClass().getSimpleName(), "noScrimView not found");
}
}
}
我的主视图在屏幕右上角的垂直 LinearLayout
中有 3 个 Button
s。每个按钮显示一些 Fragment
,这些 Fragment
位于 DrawerLayout
中。像这样:
当我单击任何按钮时,我希望 DrawerLayout 从右侧显示,并且此按钮与其一起翻译。像这样:
我已经设法将 Button
与抽屉一起移动,但我的问题是抽屉的阴影也会影响按钮。我希望它与抽屉的内容一样亮(相同高度),但我也希望其他按钮保留在抽屉后面。
这是我的activity_main.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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:fitsSystemWindows="true">
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/content_main"/>
<LinearLayout ... >
<ImageButton ... />
<ImageButton ... />
<ImageButton ... />
</LinearLayout>
<FrameLayout
android:id="@+id/fragment_secondary_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="right"
tools:context="..."/>
</android.support.v4.widget.DrawerLayout>
</android.support.design.widget.CoordinatorLayout>
有了 DrawerLayout
内的按钮,抽屉移动到它们上方,但正在翻译的那个变暗了。
另一方面,如果我将按钮放在 DrawerLayout 之外,移动的按钮看起来没问题,但抽屉位于其他按钮下方。喜欢:
有什么办法可以避免DrawerLayout的阴影影响到特定的视图吗?或者也许取消它?
DrawerLayout
在其 drawChild()
方法中将阴影 - 稀松布 - 应用于其 child View
s。它通过检查给定的 child 不是抽屉 View
来确定将其应用于哪个 children。它最终通过检查 child 的 LayoutParams
的 gravity
来做到这一点。
知道这一点,我们可以创建一个自定义 DrawerLayout
subclass 来覆盖 drawChild()
,并临时更改 child 上的 gravity
我们不想应用稀松布。由于在绘制期间没有发生布局,因此这不会影响 View
.
public class CustomDrawerLayout extends DrawerLayout {
private int noScrimId;
public CustomDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// Get the ID for the no-scrim View.
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomDrawerLayout);
noScrimId = a.getResourceId(R.styleable.CustomDrawerLayout_noScrimView, View.NO_ID);
a.recycle();
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
// Is this the child we want?
final boolean isNoScrimView = child.getId() == noScrimId;
// If yes, temporarily tag it as a drawer.
if (isNoScrimView) {
((LayoutParams) child.getLayoutParams()).gravity = Gravity.LEFT;
}
// Let the super class do the draw, and save the return.
final boolean res = super.drawChild(canvas, child, drawingTime);
// Reset the gravity if we changed it.
if (isNoScrimView) {
((LayoutParams) child.getLayoutParams()).gravity = Gravity.NO_GRAVITY;
}
return res;
}
}
此示例使用自定义属性,以便可以在布局中指定 "no-scrim" View
。如果不想使用该属性,可以从构造函数中删除 TypedArray
处理,然后硬编码一个 ID。如果你确实想使用自定义属性,你需要在你的项目中定义它,你可以通过将以下文件粘贴到 values/
文件夹中,或者添加到可能已经存在的文件中来实现。
attrs.xml
<resources>
<declare-styleable name="CustomDrawerLayout">
<attr name="noScrimView" format="reference" />
</declare-styleable>
</resources>
CustomDrawerLayout
是 drop-in 的替代品,您可以像使用常规 class 一样在布局中使用它。例如,如果您的 ImageButton
的 LinearLayout
的 ID 为 button_menu
:
<com.mycompany.myapp.CustomDrawerLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:noScrimView="@+id/button_menu">
请注意,如果您碰巧将抽屉 View
设置为 noScrimView
,您会很不高兴的。此外,noScrimView
必须是 DrawerLayout
的直接 child,因为稀松布效果仅适用于那些。
为简单起见,我省略了示例中的任何检查,但如果您希望包括一些检查,请在 onMeasure()
方法中执行它们将符合 DrawerLayout
处理它的方式自己的支票。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final View v = findViewById(noScrimId);
if (v != null) {
if (!(v.getLayoutParams() instanceof LayoutParams)) {
throw new IllegalStateException("noScrimView must be a child of DrawerLayout");
}
if (((LayoutParams) v.getLayoutParams()).gravity != Gravity.NO_GRAVITY) {
throw new IllegalStateException("noScrimView cannot be a drawer View");
}
}
else {
if (noScrimId != View.NO_ID) {
Log.d(getClass().getSimpleName(), "noScrimView not found");
}
}
}