Android Flutter上拉加载
JulyYu 人气:0前言
在此之前对列表下拉刷新做了调整方案,具体介绍可以阅读下拉刷新组件交互调整。既然列表有下拉刷新外当然还有上拉加载更多操作了,本次就来介绍如何为列表增加上拉加载更多的交互实现。
实现方案
上拉刷新实现形式上可以有多种实现方式,若不带交互形式可采用NotificationListener
组件监听滑动来实现上拉加载更多;如果对操作交互上有一定要求期望上拉刷新带有直观动画可操作性就需要实现一定样式来实现了。
监听NotificationListener实现
NotificationListener( onNotification: (scrollNotification) { if (scrollNotification.metrics.pixels >= scrollNotification.metrics.maxScrollExtent - size.height && scrollNotification.depth == 0) { if (!isLoading) { isLoading = true; Future.delayed(Duration(seconds: 1), () { isLoading = false; length += 10; Scaffold.of(context).showSnackBar(SnackBar( content: Text('下拉加载更多了!!!'), duration: Duration(milliseconds: 700), )); setState(() {}); }); } } return false; } ...... )
NotificationListener增加样式
SliverToBoxAdapter( child: Center( child: Text( length < 30 ? "加载更多...." : "没有更多", style: TextStyle(fontSize: 25), ), ), )
ScrollPhysics调整
BouncingScrollPhysics
是iOS
带有阻尼效果滑动交互,在下拉刷新中带有回弹阻尼效果是比较好的交互,但在上拉加载更多获取交互上这种效果或许有点多余。因此需要定制下拉刷新带有回弹阻尼效果,上拉加载没有回弹阻尼效果的。ScrollPhysics
CustomScrollView( physics: BouncingScrollPhysics(), slivers: <Widget>[] )
具体实现代码如下所示:
class CustomBouncingScrollPhysics extends ScrollPhysics { const CustomBouncingScrollPhysics({ ScrollPhysics parent }) : super(parent: parent); @override CustomBouncingScrollPhysics applyTo(ScrollPhysics ancestor) { return CustomBouncingScrollPhysics(parent: buildParent(ancestor)); } double frictionFactor(double overscrollFraction) => 0.52 * math.pow(1 - overscrollFraction, 2); /// 阻尼参数计算 @override double applyPhysicsToUserOffset(ScrollMetrics position, double offset) { assert(offset != 0.0); assert(position.minScrollExtent <= position.maxScrollExtent); if (!position.outOfRange) return offset; final double overscrollPastStart = math.max(position.minScrollExtent - position.pixels, 0.0); final double overscrollPastEnd = math.max(position.pixels - position.maxScrollExtent, 0.0); final double overscrollPast = math.max(overscrollPastStart, overscrollPastEnd); final bool easing = (overscrollPastStart > 0.0 && offset < 0.0) || (overscrollPastEnd > 0.0 && offset > 0.0); final double friction = easing // Apply less resistance when easing the overscroll vs tensioning. ? frictionFactor((overscrollPast - offset.abs()) / position.viewportDimension) : frictionFactor(overscrollPast / position.viewportDimension); final double direction = offset.sign; return direction * _applyFriction(overscrollPast, offset.abs(), friction); } static double _applyFriction(double extentOutside, double absDelta, double gamma) { assert(absDelta > 0); double total = 0.0; if (extentOutside > 0) { final double deltaToLimit = extentOutside / gamma; if (absDelta < deltaToLimit) return absDelta * gamma; total += extentOutside; absDelta -= deltaToLimit; } return total + absDelta; } /// 边界条件 复用ClampingScrollPhysics的方法 保留列表在底部的边界判断条件 @override double applyBoundaryConditions(ScrollMetrics position, double value){ if (position.maxScrollExtent <= position.pixels && position.pixels < value) // overscroll return value - position.pixels; if (position.pixels < position.maxScrollExtent && position.maxScrollExtent < value) // hit bottom edge return value - position.maxScrollExtent; return 0.0; } @override Simulation createBallisticSimulation(ScrollMetrics position, double velocity) { final Tolerance tolerance = this.tolerance; if (velocity.abs() >= tolerance.velocity || position.outOfRange) { return BouncingScrollSimulation( spring: spring, position: position.pixels, velocity: velocity * 0.91, // TODO(abarth): We should move this constant closer to the drag end. leadingExtent: position.minScrollExtent, trailingExtent: position.maxScrollExtent, tolerance: tolerance, ); } return null; } @override double get minFlingVelocity => kMinFlingVelocity * 2.0; @override double carriedMomentum(double existingVelocity) { return existingVelocity.sign * math.min(0.000816 * math.pow(existingVelocity.abs(), 1.967).toDouble(), 40000.0); } @override double get dragStartDistanceMotionThreshold => 3.5; }
但是直接会发生错误日志,由于回调中OverscrollIndicatorNotification
是没有metrics
对象。对于
The following NoSuchMethodError was thrown while notifying listeners for AnimationController: Class 'OverscrollIndicatorNotification' has no instance getter 'metrics'.
由于上滑没有阻尼滑动到底部回调Notification
发生了变化,因此需要在NotificationListener
中增加判断对超出滑动范围回调进行过滤处理避免异常情况发生。
if(scrollNotification is OverscrollIndicatorNotification){ return false; }
结果展示
加载全部内容