返回

底部表单拖动异常?锁定这个核心要素,彻底摆脱烦人的BUG

Android

BottomSheetDialog 拖曳冲突问题简介

一般webview的向下滑动/拖动的效果应该是可以正常显现出来的,而BottomSheetDialog控件本身自带的拖动效果也是将其整个View给消失掉的,这样两者在同时向下拖动时就会产生部分冲突。(如果没有冲突,那么必定是谷歌在设计时以及做了处理。)因此,可以把问题的解决关键集中在BottomSheetDialog的整个view上,让其不可滑动,同时让webview可以实现向上滑动。

解决问题

该问题的解决策略,包含两个方面:

  • BottomSheetDialog不可滑动

在Activity中,覆写 BottomSheetDialogbehavior() 方法。并在方法中修改其 setDraggable()false。这样做可以阻止BottomSheetDialog在向下滑动时,导致异常,而使用 BottomSheetBehavior.setPeekHeight() 控制弹出高度和显示的比例。

  • webView可以向上滑动

需要使用嵌套滚动,也就是嵌套滑动功能,实现WebView和BottomSheetDialog共存时,可以同时处理滑动事件。

  1. 定义一个NestedScrollingParent的容器, 此处以 LinearLayout 为例。
public class MyCoordinatorLayout extends LinearLayout implements NestedScrollingParent {
    public MyCoordinatorLayout(Context context) {
        super(context);
    }
    public MyCoordinatorLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public MyCoordinatorLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            mTouchY = ev.getRawY();
        }
        return super.onInterceptTouchEvent(ev);
    }
    @Override
    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL;
    }
    @Override
    public void onNestedScrollAccepted(View child, View target, int axes, int type) {
        super.onNestedScrollAccepted(child, target, axes, type);
    }
    @Override
    public void onStopNestedScroll(View target) {
        super.onStopNestedScroll(target);
    }
    @Override
    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        if (dyUnconsumed < 0) { //WebView向下滑动
            showBottomSheetDialog();
        }
        super.onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
    }
    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        return super.onNestedFling(target, velocityX, velocityY, consumed);
    }
    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        return super.onNestedPreFling(target, velocityX, velocityY);
    }
}
  1. 将上述定义的 MyCoordinatorLayout 应用于Activity布局, 其代码如下:
<com.example.nested.MyCoordinatorLayout
    android:id="@+id/parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <Button
        android:id="@+id/show_bottom_sheet"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="show_bottom_sheet" />

</com.example.nested.MyCoordinatorLayout>
  1. 给按钮设置点击监听器, 显示BottomSheetDialog:
findViewById(R.id.show_bottom_sheet).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        showBottomSheetDialog();
    }
});
  1. 显示BottomSheetDialog:
private void showBottomSheetDialog() {
    BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(MainActivity.this);
    bottomSheetDialog.setContentView(R.layout.bottom_sheet_dialog);
    BottomSheetBehavior<View> behavior = BottomSheetBehavior.from((View) bottomSheetDialog.getWindow().findViewById(R.id.design_bottom_sheet));
    behavior.setPeekHeight(300);
    behavior.setDraggable(false);
    bottomSheetDialog.show();
}

总结

通过上述操作,BottomSheetDialog和WebView都能够实现正常的使用,互不干扰。