应用栏下方的BottomSheet与应用栏滚动行为一起使用

6
我希望我的底部工具栏 `bottomsheet` 只展开到应用栏 `appbar`。我有附有选项卡的 `viewpager`,而且 `viewpager` 具有 `appbar_scrolling_view_behavior`,所以在其内部滚动列表时,`toolbar` 会折叠起来。但是底部工具栏会被展开,这不是我想要的行为。基本上,我希望折叠的 `bottomsheet` 保持原地,高度相同,在展开模式下,它应该只扩展到 `toolbar`,无论 `toolbar` 是否折叠。

这是我的 xml 格式。这可以运作,但底部工具栏也对应用栏的折叠做出相应。

如果我从第二个 `CoordinatorLayout` 中删除 behavior,则 `bottomsheet` 保持不变,但会展开到全屏幕。

<android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </android.support.design.widget.AppBarLayout>

    <FrameLayout
        android:id="@+id/loadingContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

      ... content with viewpager

    </FrameLayout>

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:id="@+id/bottomSheet"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:behavior_hideable="false"
            app:behavior_peekHeight="55dp"
            app:layout_behavior="@string/bottom_sheet_behavior"/>

    </android.support.design.widget.CoordinatorLayout>

</android.support.design.widget.CoordinatorLayout>

我也遇到了同样的问题,你有找到解决方案吗? - Sarath Kumar
我只能通过实现自己的BottomSheetBehavior来修复这个问题,该行为处理子布局。 - Datenshi
java.lang.IllegalArgumentException: 视图未与BottomSheetBehavior相关联,请发布您的xml代码。 - Sarath Kumar
1个回答

1

我自己解决了这个问题,编写了自己的行为来重新计算底部表单。还把所有元素放在了CoordinatorLayout中。

public class BottomSheetBehaviour extends AppBarLayout.ScrollingViewBehavior {

    public BottomSheetBehaviour () { }

    public BottomSheetBehaviour (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof AppBarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        setDimensions((CoordinatorLayout) child, child.getLayoutParams().width,
            parent.getHeight() - (int) getOffset(parent));
        return true;
    }

    @Override
    protected void layoutChild(final CoordinatorLayout parent, final View child, final int layoutDirection) {
        final List<View> dependencies = parent.getDependencies(child);
        final View header = findFirstDependency(dependencies);
        final Rect available = new Rect();
        if (header != null) {
            final CoordinatorLayout.LayoutParams lp =
                (CoordinatorLayout.LayoutParams) child.getLayoutParams();

            available.set(parent.getPaddingLeft() + lp.leftMargin, header.getBottom() + lp.topMargin,
                parent.getWidth() - parent.getPaddingRight() - lp.rightMargin,
                parent.getHeight() + header.getBottom() - parent.getPaddingBottom() - lp.bottomMargin);

            final Rect out = new Rect();
            GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
                child.getMeasuredHeight(), available, out, layoutDirection);
            final int overlap = getOverlapPixelsForOffset();
            child.layout(out.left, out.top - overlap, out.right, parent.getHeight() - overlap);
        }
    }

    private int getOverlapPixelsForOffset() {
        return getOverlayTop() == 0 ? 0 :
            constrain((int) (1f * getOverlayTop()), 0, getOverlayTop());
    }

    private AppBarLayout findFirstDependency(List<View> views) {
        for (int i = 0, z = views.size(); i < z; i++) {
            View view = views.get(i);
            if (view instanceof AppBarLayout) {
                return (AppBarLayout) view;
            }
        }
        return null;
    }

    private static int constrain(int amount, int low, int high) {
        return amount < low ? low : (amount > high ? high : amount);
    }

    private static int resolveGravity(int gravity) {
        return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
    }

    private void setDimensions(CoordinatorLayout view, int width, int height) {
        CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
        params.width = width;
        params.height = height;
        view.setLayoutParams(params);
    }

    private float getOffset(CoordinatorLayout coordinatorLayout) {

        for (int i = 0; i < coordinatorLayout.getChildCount(); i++) {
            View child = coordinatorLayout.getChildAt(i);

            if (child instanceof AppBarLayout) {
                return child.getY() + child.getHeight();
            }
        }
        return 0;
    }
}

解决方案有些复杂,但我没有找到任何其他更好的方法来解决这个问题。所以如果有人知道更好的解决方案,请发帖并我会进行调查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接