android support 23.2,Android support 23.2 使用BottomSheetBehavior 的坑

dim.red

新出的design:23.2.0 引入了一个新的Behavior :BottomSheetBehavior

问题

设置 BottomSheetBehavior 没有设置 PeekHeight 或者 PeekHeight为0 的时候. 底部的BottomSheetBehavior 视图滑动不出来.

分析

根据进入源码,具体的问题是

@Override

public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {

// First let the parent lay it out

if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {

parent.onLayoutChild(child, layoutDirection);

}

// Offset the bottom sheet

mParentHeight = parent.getHeight();

mMinOffset = Math.max(0, mParentHeight - child.getHeight());

mMaxOffset = mParentHeight - mPeekHeight;

if (mState == STATE_EXPANDED) {

ViewCompat.offsetTopAndBottom(child, mMinOffset);

} else if (mHideable && mState == STATE_HIDDEN) {

ViewCompat.offsetTopAndBottom(child, mParentHeight);

} else if (mState == STATE_COLLAPSED) {

ViewCompat.offsetTopAndBottom(child, mMaxOffset);

}

if (mViewDragHelper == null) {

mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);

}

mViewRef = new WeakReference<>(child);

mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));

return true;

}

一开始view 的位置是屏幕中的.因为 mState 的初始状态为STATE_COLLAPSED,mPeekHeight 为0,

mMaxOffset 变成了 rv 的高度,所以view 马上就被移出了屏幕.

然后后面View就全程透明了.很奇葩.

解决方案

解决方案 1

主动发起requestLayout 强制重绘.

behavior.setBottomSheetCallback(new BottomSheet.BottomSheetCallback() {

public boolean hasRequest;

@Override

public void onStateChanged(@NonNull View bottomSheet, int newState) {

}

@Override

public void onSlide(@NonNull View bottomSheet, float slideOffset) {

if (!hasRequest && behavior.getPeekHeight() == 0 && slideOffset > 0) {

hasRequest = true;

bottomSheet.requestLayout();

}

}

});

缺点是使用了requestLayout 方法.

解决方案2

这是幸运Science提供的

bottomSheet.setTranslationY(statusbarheight);

behavior.setBottomSheetCallback(new BottomSheet.BottomSheetCallback() {

public boolean hasRequest;

@Override

public void onStateChanged(@NonNull View bottomSheet, int newState) {

}

@Override

public void onSlide(@NonNull View bottomSheet, float slideOffset) {

if (!hasRequest && behavior.getPeekHeight() == 0 && slideOffset > 0) {

hasRequest = true;

bottomSheet.setTranslationY(0);

}

}

});

通过设置TranslationY的差值.让他重绘出来.

恍惚间记得google Design 包下有类似的解决方案,同样使用的是TranslationY差值的方式.

类:android.support.design.widget.ViewOffsetHelper

方法:updateOffsets

private void updateOffsets() {

ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));

ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));

// Manually invalidate the view and parent to make sure we get drawn pre-M

if (Build.VERSION.SDK_INT < 23) {

tickleInvalidationFlag(mView);

final ViewParent vp = mView.getParent();

if (vp instanceof View) {

tickleInvalidationFlag((View) vp);

}

}

}

private static void tickleInvalidationFlag(View view) {

final float y = ViewCompat.getTranslationY(view);

ViewCompat.setTranslationY(view, y + 1);

ViewCompat.setTranslationY(view, y);

}

可以看出这是一个23以下都有可能存在的bug.

同时需要注意的是ViewOffsetHelper是一个私有的类,updateOffsets是一个私有的方法.所以你只能copy,不能直接使用.

最终的方案

就是在方案2的基础上做一点小修改,改使用google的方案.

behavior.setBottomSheetCallback(new BottomSheet.BottomSheetCallback() {

public boolean hasRequest;

@Override

public void onStateChanged(@NonNull View bottomSheet, int newState) {

}

@Override

public void onSlide(@NonNull View bottomSheet, float slideOffset) {

if (!hasRequest && behavior.getPeekHeight() == 0 && slideOffset > 0) {

hasRequest = true;

updateOffsets(bottomSheet);

}

}

});

private void updateOffsets(View view) {

// Manually invalidate the view and parent to make sure we get drawn pre-M

if (Build.VERSION.SDK_INT < 23) {

tickleInvalidationFlag(view)

final ViewParent vp = view.getParent();

if (vp instanceof View) {

tickleInvalidationFlag((View) vp);

}

}

}

private static void tickleInvalidationFlag(View view) {

final float y = ViewCompat.getTranslationY(view);

ViewCompat.setTranslationY(view, y + 1);

ViewCompat.setTranslationY(view, y);

}

尾巴

google 在开发这个的时候应该并没有考虑这样的应用场景. 如果场景是这样的话可以是使用BottomSheetDialog 这个代替.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值