Flutter Web中PageController页面切换方法鼠标滚动触发时不生效问题
失效原因
- PageView默认会消费鼠标滚动事件处理自身滚动,和你手动调用
nextPage/previousPage的操作产生冲突,控制器的跳转指令会被原生滚动逻辑覆盖。按钮触发切换时不会同步触发PageView的原生滚动事件,不存在逻辑冲突,所以可以正常执行。 - 单次鼠标滚轮动作会连续触发多次
PointerScrollEvent,短时间内多次调用页面切换方法会导致逻辑混乱 - 你未禁用PageView自身的滚动能力,两种滚动逻辑同时作用导致跳转不生效
修复方案
- 给PageView设置
physics: const NeverScrollableScrollPhysics(),完全禁用其自身的滚动响应,所有滚动逻辑由你手动控制 - 增加节流逻辑,单次页面切换动画完成前不响应新的滚动请求,避免连续触发
- 将组件改为StatefulWidget,便于存储控制器和节流状态,同时补充控制器销毁逻辑避免内存泄漏
修复后完整代码
import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart' show kIsWeb; class MainView extends StatefulWidget { const MainView({Key? key}) : super(key: key); @override State<MainView> createState() => _MainViewState(); } class _MainViewState extends State<MainView> { final PageController controller = PageController(initialPage: 0); // 节流标记,跳转过程中禁止响应新的滚动请求 bool _isScrolling = false; @override Widget build(BuildContext context) { if (kIsWeb) { return Listener( onPointerSignal: (pointerSignal) async { if (pointerSignal is PointerScrollEvent && !_isScrolling) { _isScrolling = true; if (pointerSignal.scrollDelta.dy > 0) { // 向下滚动切换下一页 await controller.nextPage( duration: const Duration(milliseconds: 500), curve: Curves.ease); } else if (pointerSignal.scrollDelta.dy < 0) { // 向上滚动切换上一页 await controller.previousPage( duration: const Duration(milliseconds: 500), curve: Curves.ease); } // 动画结束后重置节流标记 _isScrolling = false; } }, child: PageView( scrollDirection: Axis.vertical, pageSnapping: false, controller: controller, // 禁用PageView自身滚动能力 physics: const NeverScrollableScrollPhysics(), children: const <Widget>[ Center( child: Text('First Page'), ), Center( child: Text('Second Page'), ), Center( child: Text('Third Page'), ) ], ), ); } else { return const Container(); } } @override void dispose() { controller.dispose(); super.dispose(); } }
内容的提问来源于stack exchange,提问作者Emad Husam Eldeen
相关产品推荐
相关产品推荐

