ViewPager滑动禁用后在特定Fragment布局中卡顿问题求助
这个问题我之前也碰到过,你用setOnTouchListener返回true的方式禁用滑动,在大部分Fragment里生效,但遇到带ScrollView的布局就失灵,核心原因是触摸事件的传递优先级问题:ScrollView会优先拦截并处理滑动事件,导致ViewPager的OnTouchListener根本没机会拿到这些事件,所以ViewPager还是会响应横向滑动,甚至出现卡在两个Fragment之间的情况。
下面给你两个可靠的解决方案,优先推荐第一个:
方案一:自定义不可滑动的ViewPager(最稳妥)
直接重写ViewPager的事件拦截和处理方法,从根源上禁用它的滑动功能,不管子布局有没有滚动控件,都能生效。
步骤1:创建自定义ViewPager类
public class NonSwipeableViewPager extends ViewPager { public NonSwipeableViewPager(Context context) { super(context); } public NonSwipeableViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { // 不拦截任何触摸事件,彻底切断ViewPager对滑动事件的处理 return false; } @Override public boolean onTouchEvent(MotionEvent event) { // 不处理任何触摸事件,让事件继续传递或被消费 return false; } }
步骤2:替换布局中的ViewPager
把原来布局里的androidx.viewpager.widget.ViewPager替换成你自定义的类(注意替换成你的实际包名):
<com.your.app.package.NonSwipeableViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" />
这样修改后,ViewPager的滑动功能就完全被禁用了,不管哪个Fragment里的布局,都不会再出现滑动触发的问题。
方案二:给ScrollView添加触摸事件处理(临时适配)
如果你不想修改ViewPager的实现,可以针对这个含ScrollView的Fragment单独处理,让ScrollView在横向滑动时把事件交还给ViewPager:
在HrLinkFragment的onViewCreated方法中添加以下代码:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ScrollView scrollView = view.findViewById(R.id.scroll_view); // 给你的ScrollView设置id scrollView.setOnTouchListener(new View.OnTouchListener() { private float startX; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX(); // 允许父View(ViewPager)拦截事件 v.getParent().requestDisallowInterceptTouchEvent(false); break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(event.getX() - startX); // 如果是横向滑动(超过阈值),让ViewPager拦截事件 if (dx > 10) { // 10为滑动阈值,可根据需求调整 v.getParent().requestDisallowInterceptTouchEvent(false); } else { // 纵向滑动时,不让ViewPager拦截,保证ScrollView正常滚动 v.getParent().requestDisallowInterceptTouchEvent(true); } break; } return false; // 让ScrollView处理自身的触摸事件 } }); }
注意要给布局里的ScrollView加上android:id="@+id/scroll_view"的属性,不然找不到这个控件。
这个方案是临时适配,适合不想全局修改ViewPager的场景,但不如方案一稳定,比如滑动方向判断的阈值可能需要根据不同设备调整。
内容的提问来源于stack exchange,提问作者Marlon

