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可以滑动。