如何使用相同的 Z 将 View 与 DrawerLayout 内容一起移动

How move View alongside DrawerLayout's content whit the same Z

我的主视图在屏幕右上角的垂直 LinearLayout 中有 3 个 Buttons。每个按钮显示一些 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 Views。它通过检查给定的 child 不是抽屉 View 来确定将其应用于哪个 children。它最终通过检查 child 的 LayoutParamsgravity 来做到这一点。

知道这一点,我们可以创建一个自定义 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 一样在布局中使用它。例如,如果您的 ImageButtonLinearLayout 的 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");
        }
    }
}