如何在用户仍滚动时取消ViewPager的正在进行的滚动操作?
车载Android系统ViewPager滚动中断问题
背景
我们团队采用Android平板作为车载系统显示屏,仪表盘里有一个用ViewPager实现的「小部件轮播(widget carousel)」,用户可左右滑动切换显示的小部件。车辆静止时用户能自由滚动轮播,车辆行驶时需要屏蔽屏幕交互,引导用户专注驾驶。
问题
如果用户正在滚动时车辆启动,当前的滚动操作不会被中断,用户仍能继续滚动直到松开手,再次触摸屏幕时交互才会被正确屏蔽。
需求
我查过不少Stack Overflow帖子,多数方案只能阻止新的滚动操作,没法取消正在进行中的滚动。**有没有办法在用户仍滚动时直接中断当前滚动?**我自己已经有一套可行方案,也欢迎其他方案或对现有方案的改进建议,帮后续遇到同类问题的开发者。
可行解决方案
方案1:强制终止滚动+禁用交互
当检测到车辆启动时,通过ViewPager的伪拖拽机制中断当前滚动,同时禁用后续触摸交互:
// 针对原生ViewPager ViewPager viewPager = ...; // 中断正在进行的滚动 if (viewPager.isFakeDragging()) { viewPager.endFakeDrag(); } else { if (viewPager.beginFakeDrag()) { viewPager.endFakeDrag(); } } // 禁用后续触摸 viewPager.setOnTouchListener((v, event) -> true); // 如果是ViewPager2,代码更简洁: // ViewPager2 viewPager2 = ...; // viewPager2.setUserInputEnabled(false); // viewPager2.scrollToPosition(viewPager2.getCurrentItem());
方案2:自定义可拦截的ViewPager
重写ViewPager,增加状态控制变量,一键终止滚动并拦截后续触摸:
public class BlockableViewPager extends ViewPager { private boolean isInteractionBlocked = false; public BlockableViewPager(Context context) { super(context); } public BlockableViewPager(Context context, AttributeSet attrs) { super(context, attrs); } public void setInteractionBlocked(boolean blocked) { isInteractionBlocked = blocked; if (blocked) { // 终止滚动 if (isFakeDragging()) { endFakeDrag(); } else if (beginFakeDrag()) { endFakeDrag(); } stopScroll(); } } @Override public boolean onTouchEvent(MotionEvent ev) { return !isInteractionBlocked && super.onTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return !isInteractionBlocked && super.onInterceptTouchEvent(ev); } }
使用时只需在车辆启动时调用blockableViewPager.setInteractionBlocked(true),即可立即终止滚动并屏蔽后续操作。
方案3:无动画跳转当前页面终止滚动
直接让ViewPager无动画跳转到当前显示的页面,强制中断滚动动画和用户触摸:
int currentPage = viewPager.getCurrentItem(); // 第二个参数传false,无动画跳转,直接终止滚动 viewPager.setCurrentItem(currentPage, false); // 禁用后续触摸 viewPager.setOnTouchListener((v, event) -> true);
内容的提问来源于stack exchange,提问作者Eric Schnipke
相关产品推荐
相关产品推荐

