注意:这里以ListView横向滑动分页为列子
**思路:**给可滑动的组件添加滑动监控,依据手势不同状态下的滚动决定滚动的位置
-
用Listener组件包裹ListView,
Listener( child: ListView.builder(), )
-
Listener提供了几个接口来进行手势回调
// 按下 final PointerDownEventListener onPointerDown; // 滑动 final PointerMoveEventListener onPointerMove; // 抬起 final PointerUpEventListener onPointerUp; Expanded( child: Listener( onPointerDown: getPointDownListenerInHorizontal(), onPointerUp: getPointUpListenerInHorizontal(), ))
-
ListView的controller属性是用来控制滚动的,接受一个ScrollController对象,默认值是PrimaryScrollController
// 设置全局变量 ScrollController _scrollController = ScrollController(); 。。。 child: ListView.builder( scrollDirection: Axis.horizontal, controller: _scrollController, // 赋值控制对象 itemCount: menuTitles.length, itemExtent: screenWidth, itemBuilder: (context, index) { return Container( decoration: BoxDecoration(color: Colors.red), child: Center( child: Text(menuTitles[index]), ), ); }, ),
-
相应的滚动事件的处理
Offset pointerStart; // 记录当前按下的点 Offset pointerEnd; // 记录抬起的点 double touchRangeX = 0; // 比较x方向上的偏移,根据这个值来判断是否翻页 double nextOffset = 0; int lastPage = 0; // 记录当前显示的页,默认是0 // 按下时保存当前的点 PointerDownEventListener getPointDownListenerInHorizontal() { return (event) { pointerStart = event.position; }; } // 抬起时触发 PointerUpEventListener getPointUpListenerInHorizontal() { return (event) { pointerEnd = event.position; touchRangeX = pointerStart.dx - pointerEnd.dx; if (touchRangeX.abs() < screenWidth / 8) { // 滑动距离大于屏幕宽度的1/8就可以继续翻页了 nextOffset = screenWidth * lastPage; animateToOffset(_scrollController, nextOffset, null); return; } if (touchRangeX < 0 && lastPage > 0) { // 手指从左向右滑动 lastPage--; animateToOffset(_scrollController, lastPage * screenWidth, null); } else if (touchRangeX > 0 && lastPage < menuTitles.length - 1) { // 从右向左 lastPage++; animateToOffset(_scrollController, lastPage * screenWidth, null); } };
-
滚动到指定的位置
void animateToOffset(ScrollController controller, double offset, void Function() onScrollCompleted) { controller .animateTo(offset, duration: Duration(milliseconds: 200), curve: Curves.easeIn) .then((value) { if (onScrollCompleted != null) { onScrollCompleted(); } }).catchError((e) { print(e); }); }
-
所有代码
import 'dart:convert'; import 'package:flutter/material.dart'; class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { String contentText = "正在加载数据"; ScrollController _scrollController = ScrollController(); double screenWidth = 375; @override Widget build(BuildContext context) { screenWidth = MediaQuery.of(context).size.width; return Scaffold( appBar: AppBar(title: Text("title")), body: Column( children: <Widget>[ Expanded( child: Listener( onPointerDown: getPointDownListenerInHorizontal(), onPointerUp: getPointUpListenerInHorizontal(), child: ListView.builder( scrollDirection: Axis.horizontal, controller: _scrollController, itemCount: menuTitles.length, itemExtent: screenWidth, itemBuilder: (context, index) { return Container( decoration: BoxDecoration(color: Colors.red), child: Center( child: Text(menuTitles[index]), ), ); }, ), )) ], )); } //获取屏幕宽度 Offset pointerStart; Offset pointerEnd; double touchRangeX = 0; double nextOffset = 0; int lastPage = 0; PointerDownEventListener getPointDownListenerInHorizontal() { return (event) { pointerStart = event.position; }; } PointerUpEventListener getPointUpListenerInHorizontal() { return (event) { pointerEnd = event.position; touchRangeX = pointerStart.dx - pointerEnd.dx; if (touchRangeX.abs() < screenWidth / 8) { nextOffset = screenWidth * lastPage; animateToOffset(_scrollController, nextOffset, null); } if (touchRangeX < 0 && lastPage > 0) { // l2r lastPage--; animateToOffset(_scrollController, lastPage * screenWidth, null); } else if (touchRangeX > 0 && lastPage < menuTitles.length - 1) { // r2l lastPage++; animateToOffset(_scrollController, lastPage * screenWidth, null); } }; } void animateToOffset(ScrollController controller, double offset, void Function() onScrollCompleted) { controller .animateTo(offset, duration: Duration(milliseconds: 200), curve: Curves.easeIn) .then((value) { if (onScrollCompleted != null) { onScrollCompleted(); } }).catchError((e) { print(e); }); } }