解决一个ImageViewTouch和Viewpager2滑动冲突问题

156 阅读2分钟

ViewPager在配套使用 ImageViewTouch时遇到滑动冲突问题,官方给的解决方案是



class ExtendedViewPager : ViewPager {

    constructor(context: Context) : super(context)

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

    override fun canScroll(view: View, checkV: Boolean, dx: Int, x: Int, y: Int): Boolean {
        return if (view is TouchImageView) {
            view.canScrollHorizontally(-dx)
        } else {
            super.canScroll(view, checkV, dx, x, y)
        }
    }

}

在canScroll方法中判断如果 参数v是ImageViewTouch的话,需要判断 ImageViewTouch自身是否可以滑动,

项目用的是比较老的版本,代码是:


public class PreviewViewPager extends ViewPager {

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

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        if (v instanceof ImageViewTouch) {
            return ((ImageViewTouch) v).canScroll(dx) || super.canScroll(v, checkV, dx, x, y);
        }
        return super.canScroll(v, checkV, dx, x, y);
    }
}


现在项目优化 ViewPager升级成ViewPager2 ,Viewpager2被final修饰不能重写。

官方解决滑动冲突的代码


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return ViewHolder(TouchImageView(parent.context).apply {
        layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)

        setOnTouchListener { view, event ->
            var result = true
            //can scroll horizontally checks if there's still a part of the image
            //that can be scrolled until you reach the edge
            if (event.pointerCount >= 2 || view.canScrollHorizontally(1) && canScrollHorizontally(-1)) {
                //multi-touch event
                result = when (event.action) {
                    MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
                        // Disallow RecyclerView to intercept touch events.
                        parent.requestDisallowInterceptTouchEvent(true)
                        // Disable touch on view
                        false
                    }
                    MotionEvent.ACTION_UP -> {
                        // Allow RecyclerView to intercept touch events.
                        parent.requestDisallowInterceptTouchEvent(false)
                        true
                    }
                    else -> true
                }
            }
            result
        }
    })
}

官方demo直接使用的是 RecyclerView.Adapter 但是项目中使用的是FragmentStateAdapter 最终的解决滑动冲突的代码是


image.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        boolean result = true;
        if (event.getPointerCount() >= 2 ||  image.canScroll(1) && image.canScroll(-1)) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_MOVE:
                    updateRecyclerViewDisallowInterceptTouchEvent(image,true);
                    result = false;
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    updateRecyclerViewDisallowInterceptTouchEvent(image,false);
                    result = true;
                    break;
                default:
                    result = true;
                    break;
            }
        }
        return result;
    }
});


这里的逻辑是 当两个以上手指滑动的时候禁止父View,也就是Viewpager2(RecyclerView)禁止滑动。图片放大。

当图片同时可以左右滑动的时候同理也要禁止ViewPager2滑动,只能本身图片滑动。

当图片左右不是都可以滑动的话,说明图片没有放大,或者图片放大后已经滑动到了一侧。这时候单手指滑动。如果向图片不可滑动那一侧滑动,则不会进入onTouch中的代码逻辑,也就是直接滑动Viewpager2。

如果向Image可以滑动的那一侧滑动,则MotionEvent.ACTION_DOWN时不会触发onTouch中的代码逻辑,但是MotionEvent.ACTION_MOVE时触发 updateRecyclerViewDisallowInterceptTouchEvent(image,true);禁止ViewPage2滑动,这时Image可以滑动。