123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785 |
- import 'dart:async';
- import 'dart:math';
- import 'package:eye_video/framework/uikit/refresher/pretty_refresher.dart';
- import 'package:flutter/rendering.dart';
- import 'package:flutter/scheduler.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter/widgets.dart';
- class _SliverRefresh extends SingleChildRenderObjectWidget {
- const _SliverRefresh({
- Key? key,
- this.refreshIndicatorLayoutExtent = 0.0,
- this.hasLayoutExtent = false,
- this.enableInfiniteRefresh = false,
- this.headerFloat = false,
- this.axisDirectionNotifier,
- required this.infiniteRefresh,
- Widget child,
- }) : assert(refreshIndicatorLayoutExtent != null),
- assert(refreshIndicatorLayoutExtent >= 0.0),
- assert(hasLayoutExtent != null),
- super(key: key, child: child);
- // The amount of space the indicator should occupy in the sliver in a
- // resting state when in the refreshing mode.
- final double refreshIndicatorLayoutExtent;
- // _RenderRefreshSliverRefresh will paint the child in the available
- // space either way but this instructs the _RenderRefreshSliverRefresh
- // on whether to also occupy any layoutExtent space or not.
- final bool hasLayoutExtent;
- // 是否开启无限刷新
- final bool enableInfiniteRefresh;
- // 无限加载回调
- final VoidCallback infiniteRefresh;
- // Header浮动
- final bool headerFloat;
- // 列表方向
- final ValueNotifier<AxisDirection> axisDirectionNotifier;
- @override
- _RenderRefreshSliverRefresh createRenderObject(BuildContext context) {
- return _RenderRefreshSliverRefresh(
- refreshIndicatorExtent: refreshIndicatorLayoutExtent,
- hasLayoutExtent: hasLayoutExtent,
- enableInfiniteRefresh: enableInfiniteRefresh,
- infiniteRefresh: infiniteRefresh,
- headerFloat: headerFloat,
- axisDirectionNotifier: axisDirectionNotifier,
- );
- }
- @override
- void updateRenderObject(BuildContext context,
- covariant _RenderRefreshSliverRefresh renderObject) {
- renderObject
- ..refreshIndicatorLayoutExtent = refreshIndicatorLayoutExtent
- ..hasLayoutExtent = hasLayoutExtent
- ..enableInfiniteRefresh = enableInfiniteRefresh
- ..headerFloat = headerFloat;
- }
- }
- // RenderSliver object that gives its child RenderBox object space to paint
- // in the overscrolled gap and may or may not hold that overscrolled gap
- // around the RenderBox depending on whether [layoutExtent] is set.
- //
- // The [layoutExtentOffsetCompensation] field keeps internal accounting to
- // prevent scroll position jumps as the [layoutExtent] is set and unset.
- class _RenderRefreshSliverRefresh extends RenderSliverSingleBoxAdapter {
- _RenderRefreshSliverRefresh({
- required double refreshIndicatorExtent,
- required bool hasLayoutExtent,
- required bool enableInfiniteRefresh,
- required this.infiniteRefresh,
- required bool headerFloat,
- required this.axisDirectionNotifier,
- RenderBox child,
- }) : assert(refreshIndicatorExtent != null),
- assert(refreshIndicatorExtent >= 0.0),
- assert(hasLayoutExtent != null),
- _refreshIndicatorExtent = refreshIndicatorExtent,
- _enableInfiniteRefresh = enableInfiniteRefresh,
- _hasLayoutExtent = hasLayoutExtent,
- _headerFloat = headerFloat {
- this.child = child;
- }
- // The amount of layout space the indicator should occupy in the sliver in a
- // resting state when in the refreshing mode.
- double get refreshIndicatorLayoutExtent => _refreshIndicatorExtent;
- double _refreshIndicatorExtent;
- set refreshIndicatorLayoutExtent(double value) {
- assert(value != null);
- assert(value >= 0.0);
- if (value == _refreshIndicatorExtent) return;
- _refreshIndicatorExtent = value;
- markNeedsLayout();
- }
- // 列表方向
- final ValueNotifier<AxisDirection> axisDirectionNotifier;
- // The child box will be laid out and painted in the available space either
- // way but this determines whether to also occupy any
- // [SliverGeometry.layoutExtent] space or not.
- bool get hasLayoutExtent => _hasLayoutExtent;
- bool _hasLayoutExtent;
- set hasLayoutExtent(bool value) {
- assert(value != null);
- if (value == _hasLayoutExtent) return;
- _hasLayoutExtent = value;
- markNeedsLayout();
- }
- // 是否开启无限刷新
- bool get enableInfiniteRefresh => _enableInfiniteRefresh;
- bool _enableInfiniteRefresh;
- set enableInfiniteRefresh(bool value) {
- assert(value != null);
- if (value == _enableInfiniteRefresh) return;
- _enableInfiniteRefresh = value;
- markNeedsLayout();
- }
- // Header是否浮动
- bool get headerFloat => _headerFloat;
- bool _headerFloat;
- set headerFloat(bool value) {
- assert(value != null);
- if (value == _headerFloat) return;
- _headerFloat = value;
- markNeedsLayout();
- }
- // 无限加载回调
- final VoidCallback infiniteRefresh;
- // 触发无限刷新
- bool _triggerInfiniteRefresh = false;
- // 获取子组件大小
- double get childSize =>
- constraints.axis == Axis.vertical ? child.size.height : child.size.width;
- // This keeps track of the previously applied scroll offsets to the scrollable
- // so that when [refreshIndicatorLayoutExtent] or [hasLayoutExtent] changes,
- // the appropriate delta can be applied to keep everything in the same place
- // visually.
- double layoutExtentOffsetCompensation = 0.0;
- @override
- double get centerOffsetAdjustment {
- // Header浮动时去掉越界
- if (headerFloat) {
- final RenderViewportBase renderViewport = parent;
- return max(0.0, -renderViewport.offset.pixels);
- }
- return super.centerOffsetAdjustment;
- }
- @override
- void layout(Constraints constraints, {bool parentUsesSize = false}) {
- // Header浮动时保持刷新
- if (headerFloat) {
- final RenderViewportBase renderViewport = parent;
- super.layout(
- (constraints as SliverConstraints)
- .copyWith(overlap: min(0.0, renderViewport.offset.pixels)),
- parentUsesSize: true);
- } else {
- super.layout(constraints, parentUsesSize: parentUsesSize);
- }
- }
- @override
- void performLayout() {
- // Only pulling to refresh from the top is currently supported.
- // 注释以支持reverse
- // assert(constraints.axisDirection == AxisDirection.down);
- axisDirectionNotifier.value = constraints.axisDirection;
- assert(constraints.growthDirection == GrowthDirection.forward);
- // 判断是否触发无限刷新
- if (enableInfiniteRefresh &&
- constraints.scrollOffset < _refreshIndicatorExtent &&
- constraints.userScrollDirection != ScrollDirection.idle) {
- if (!_triggerInfiniteRefresh) {
- _triggerInfiniteRefresh = true;
- infiniteRefresh();
- }
- } else {
- if (constraints.scrollOffset > _refreshIndicatorExtent) {
- if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) {
- _triggerInfiniteRefresh = false;
- } else {
- SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
- _triggerInfiniteRefresh = false;
- });
- }
- }
- }
- // The layout extent this sliver should now have.
- final double layoutExtent =
- (_hasLayoutExtent || enableInfiniteRefresh ? 1.0 : 0.0) *
- _refreshIndicatorExtent;
- // If the layoutExtent instructive changed, the SliverGeometry's
- // layoutExtent will take that value (on the next performLayout run). Shift
- // the scroll offset first so it doesn't make the scroll position suddenly jump.
- // 如果Header浮动则不用过渡
- if (!headerFloat) {
- if (layoutExtent != layoutExtentOffsetCompensation) {
- geometry = SliverGeometry(
- scrollOffsetCorrection: layoutExtent - layoutExtentOffsetCompensation,
- );
- layoutExtentOffsetCompensation = layoutExtent;
- // Return so we don't have to do temporary accounting and adjusting the
- // child's constraints accounting for this one transient frame using a
- // combination of existing layout extent, layout extent change and
- // the overlap.
- return;
- }
- }
- final bool active = constraints.overlap < 0.0 || layoutExtent > 0.0;
- final double overscrolledExtent =
- constraints.overlap < 0.0 ? constraints.overlap.abs() : 0.0;
- // Layout the child giving it the space of the currently dragged overscroll
- // which may or may not include a sliver layout extent space that it will
- // keep after the user lets go during the refresh process.
- // Header浮动时不用layoutExtent,不然会有跳动
- if (headerFloat) {
- child.layout(
- constraints.asBoxConstraints(
- maxExtent: _hasLayoutExtent
- ? overscrolledExtent > _refreshIndicatorExtent
- ? overscrolledExtent
- // 如果为double.infinity则占满列表
- : _refreshIndicatorExtent == double.infinity
- ? constraints.viewportMainAxisExtent
- : _refreshIndicatorExtent
- : overscrolledExtent,
- ),
- parentUsesSize: true,
- );
- } else {
- child.layout(
- constraints.asBoxConstraints(
- maxExtent: layoutExtent
- // Plus only the overscrolled portion immediately preceding this
- // sliver.
- +
- overscrolledExtent,
- ),
- parentUsesSize: true,
- );
- }
- if (active) {
- // 判断Header是否浮动
- if (headerFloat) {
- geometry = SliverGeometry(
- scrollExtent: 0.0,
- paintOrigin: 0.0,
- paintExtent: childSize,
- maxPaintExtent: childSize,
- layoutExtent: max(-constraints.scrollOffset, 0.0),
- visible: true,
- hasVisualOverflow: true,
- );
- } else {
- geometry = SliverGeometry(
- scrollExtent: layoutExtent,
- paintOrigin: -overscrolledExtent - constraints.scrollOffset,
- paintExtent: min(
- max(
- // Check child size (which can come from overscroll) because
- // layoutExtent may be zero. Check layoutExtent also since even
- // with a layoutExtent, the indicator builder may decide to not
- // build anything.
- max(childSize, layoutExtent) - constraints.scrollOffset,
- 0.0,
- ),
- constraints.remainingPaintExtent),
- maxPaintExtent: max(
- max(childSize, layoutExtent) - constraints.scrollOffset,
- 0.0,
- ),
- layoutExtent: max(layoutExtent - constraints.scrollOffset, 0.0),
- );
- }
- } else {
- // If we never started overscrolling, return no geometry.
- geometry = SliverGeometry.zero;
- }
- }
- @override
- void paint(PaintingContext paintContext, Offset offset) {
- if (constraints.overlap < 0.0 || constraints.scrollOffset + childSize > 0) {
- paintContext.paintChild(child, offset);
- }
- }
- // Nothing special done here because this sliver always paints its child
- // exactly between paintOrigin and paintExtent.
- @override
- void applyPaintTransform(RenderObject child, Matrix4 transform) {}
- }
- enum RefreshMode {
- // Initial state, when not being overscrolled into, or after the overscroll
- // is canceled or after done and the sliver retracted away.
- inactive,
- // While being overscrolled but not far enough yet to trigger the refresh.
- drag,
- // Dragged far enough that the onRefresh callback will run and the dragged
- // displacement is not yet at the final refresh resting state.
- armed,
- // While the onRefresh task is running.
- refresh,
- // 刷新完成
- refreshed,
- // While the indicator is animating away after refreshing.
- done,
- }
- typedef RefreshControlBuilder = Widget Function(
- BuildContext context,
- RefreshMode refreshState,
- double pulledExtent,
- double refreshTriggerPullDistance,
- double refreshIndicatorExtent,
- AxisDirection axisDirection,
- bool float,
- Duration completeDuration,
- bool enableInfiniteRefresh,
- bool success,
- bool noMore);
- typedef OnRefreshCallback = Future<void> Function();
- // 结束刷新
- // success 为是否成功(为false时,noMore无效)
- // noMore 为是否有更多数据
- typedef FinishRefresh = void Function({
- bool success,
- bool noMore,
- });
- // 绑定刷新指示剂
- typedef BindRefreshIndicator = void Function(
- FinishRefresh finishRefresh, VoidCallback resetRefreshState);
- class RefreshSliverRefreshControl extends StatefulWidget {
- const RefreshSliverRefreshControl({
- Key? key,
- this.refreshTriggerPullDistance = _defaultRefreshTriggerPullDistance,
- this.refreshIndicatorExtent = _defaultRefreshIndicatorExtent,
- required this.builder,
- this.completeDuration,
- this.onRefresh,
- this.focusNotifier,
- this.taskNotifier,
- this.callRefreshNotifier,
- this.taskIndependence,
- this.bindRefreshIndicator,
- this.enableControlFinishRefresh = false,
- this.enableInfiniteRefresh = false,
- this.enableHapticFeedback = false,
- this.headerFloat = false,
- }) : assert(refreshTriggerPullDistance != null),
- assert(refreshTriggerPullDistance > 0.0),
- assert(refreshIndicatorExtent != null),
- assert(refreshIndicatorExtent >= 0.0),
- assert(
- headerFloat || refreshTriggerPullDistance >= refreshIndicatorExtent,
- 'The refresh indicator cannot take more space in its final state '
- 'than the amount initially created by overscrolling.'),
- super(key: key);
- final double refreshTriggerPullDistance;
- final double refreshIndicatorExtent;
- final RefreshControlBuilder builder;
- final OnRefreshCallback onRefresh;
- // 完成延时
- final Duration completeDuration;
- // 绑定刷新指示器
- final BindRefreshIndicator bindRefreshIndicator;
- // 是否开启控制结束
- final bool enableControlFinishRefresh;
- // 是否开启无限刷新
- final bool enableInfiniteRefresh;
- // 开启震动反馈
- final bool enableHapticFeedback;
- // 滚动状态
- final ValueNotifier<bool> focusNotifier;
- // 触发刷新状态
- final ValueNotifier<bool> callRefreshNotifier;
- // 任务状态
- final ValueNotifier<TaskState> taskNotifier;
- // 是否任务独立
- final bool taskIndependence;
- // Header浮动
- final bool headerFloat;
- static const double _defaultRefreshTriggerPullDistance = 100.0;
- static const double _defaultRefreshIndicatorExtent = 60.0;
- // Retrieve the current state of the RefreshSliverRefreshControl. The same as the
- // state that gets passed into the [builder] function. Used for testing.
- /*@visibleForTesting
- static RefreshMode state(BuildContext context) {
- final _RefreshSliverRefreshControlState state = context
- .findAncestorStateOfType<_RefreshSliverRefreshControlState>();
- return state.refreshState;
- }*/
- @override
- _RefreshSliverRefreshControlState createState() =>
- _RefreshSliverRefreshControlState();
- }
- class _RefreshSliverRefreshControlState
- extends State<RefreshSliverRefreshControl> {
- // Reset the state from done to inactive when only this fraction of the
- // original `refreshTriggerPullDistance` is left.
- static const double _inactiveResetOverscrollFraction = 0.1;
- RefreshMode refreshState;
- // [Future] returned by the widget's `onRefresh`.
- Future<void> _refreshTask;
- Future<void> get refreshTask => _refreshTask;
- bool get hasTask {
- return widget.taskIndependence
- ? _refreshTask != null
- : widget.taskNotifier.value.loading ||
- widget.taskNotifier.value.refreshing;
- }
- set refreshTask(Future<void> task) {
- _refreshTask = task;
- if (!widget.taskIndependence) {
- widget.taskNotifier.value =
- widget.taskNotifier.value.copy(refreshing: task != null);
- }
- }
- // The amount of space available from the inner indicator box's perspective.
- //
- // The value is the sum of the sliver's layout extent and the overscroll
- // (which partially gets transferred into the layout extent when the refresh
- // triggers).
- //
- // The value of latestIndicatorBoxExtent doesn't change when the sliver scrolls
- // away without retracting; it is independent from the sliver's scrollOffset.
- double latestIndicatorBoxExtent = 0.0;
- bool hasSliverLayoutExtent = false;
- // 滚动焦点
- bool get _focus => widget.focusNotifier.value;
- // 刷新完成
- bool _success;
- // 没有更多数据
- bool _noMore;
- // 列表方向
- ValueNotifier<AxisDirection> _axisDirectionNotifier;
- // 初始化
- @override
- void initState() {
- super.initState();
- refreshState = RefreshMode.inactive;
- _axisDirectionNotifier = ValueNotifier<AxisDirection>(AxisDirection.down);
- // 绑定刷新指示器
- if (widget.bindRefreshIndicator != null) {
- widget.bindRefreshIndicator(finishRefresh, resetRefreshState);
- }
- }
- // 销毁
- @override
- void dispose() {
- super.dispose();
- }
- // 完成刷新
- void finishRefresh({
- bool success,
- bool noMore,
- }) {
- _success = success;
- _noMore = _success == false ? false : noMore;
- widget.taskNotifier.value =
- widget.taskNotifier.value.copy(refreshNoMore: _noMore);
- if (widget.enableControlFinishRefresh && refreshTask != null) {
- if (widget.enableInfiniteRefresh) {
- refreshState = RefreshMode.inactive;
- }
- setState(() => refreshTask = null);
- refreshState = transitionNextState();
- }
- }
- // 恢复状态
- void resetRefreshState() {
- if (mounted) {
- setState(() {
- _success = true;
- _noMore = false;
- refreshState = RefreshMode.inactive;
- hasSliverLayoutExtent = false;
- });
- }
- }
- // 无限刷新
- void _infiniteRefresh() {
- if (!hasTask &&
- widget.enableInfiniteRefresh &&
- _noMore != true &&
- !widget.callRefreshNotifier.value) {
- if (widget.enableHapticFeedback) {
- HapticFeedback.mediumImpact();
- }
- SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
- refreshState = RefreshMode.refresh;
- refreshTask = widget.onRefresh()
- ..then((_) {
- if (mounted && !widget.enableControlFinishRefresh) {
- refreshState = RefreshMode.refresh;
- setState(() => refreshTask = null);
- // Trigger one more transition because by this time, BoxConstraint's
- // maxHeight might already be resting at 0 in which case no
- // calls to [transitionNextState] will occur anymore and the
- // state may be stuck in a non-inactive state.
- refreshState = transitionNextState();
- }
- });
- setState(() => hasSliverLayoutExtent = true);
- });
- }
- }
- // A state machine transition calculator. Multiple states can be transitioned
- // through per single call.
- RefreshMode transitionNextState() {
- RefreshMode nextState;
- // 判断是否没有更多
- if (_noMore == true && widget.enableInfiniteRefresh) {
- return refreshState;
- } else if (_noMore == true &&
- refreshState != RefreshMode.refresh &&
- refreshState != RefreshMode.refreshed &&
- refreshState != RefreshMode.done) {
- return refreshState;
- } else if (widget.enableInfiniteRefresh &&
- refreshState == RefreshMode.done) {
- return RefreshMode.inactive;
- }
- // 结束
- void goToDone() {
- nextState = RefreshMode.done;
- refreshState = RefreshMode.done;
- // Either schedule the RenderSliver to re-layout on the next frame
- // when not currently in a frame or schedule it on the next frame.
- if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) {
- setState(() => hasSliverLayoutExtent = false);
- } else {
- SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
- setState(() => hasSliverLayoutExtent = false);
- });
- }
- }
- // 完成
- RefreshMode goToFinish() {
- // 判断刷新完成
- RefreshMode state = RefreshMode.refreshed;
- // 添加延时
- if (widget.completeDuration == null || widget.enableInfiniteRefresh) {
- goToDone();
- return null;
- } else {
- Future.delayed(widget.completeDuration, () {
- if (mounted) {
- goToDone();
- }
- });
- return state;
- }
- }
- switch (refreshState) {
- case RefreshMode.inactive:
- if (latestIndicatorBoxExtent <= 0 ||
- (!_focus && !widget.callRefreshNotifier.value)) {
- return RefreshMode.inactive;
- } else {
- if (widget.callRefreshNotifier.value) {
- widget.callRefreshNotifier.value = false;
- }
- nextState = RefreshMode.drag;
- }
- continue drag;
- drag:
- case RefreshMode.drag:
- if (latestIndicatorBoxExtent == 0) {
- return RefreshMode.inactive;
- } else if (latestIndicatorBoxExtent <=
- widget.refreshTriggerPullDistance) {
- // 如果未触发刷新则取消固定高度
- if (hasSliverLayoutExtent && !hasTask) {
- SchedulerBinding.instance
- .addPostFrameCallback((Duration timestamp) {
- setState(() => hasSliverLayoutExtent = false);
- });
- }
- return RefreshMode.drag;
- } else {
- // 提前固定高度,防止列表回弹
- SchedulerBinding.instance.addPostFrameCallback((Duration timestamp) {
- if (!hasSliverLayoutExtent) {
- setState(() => hasSliverLayoutExtent = true);
- }
- });
- if (widget.onRefresh != null && !hasTask) {
- if (!_focus) {
- if (widget.callRefreshNotifier.value) {
- widget.callRefreshNotifier.value = false;
- }
- if (widget.enableHapticFeedback) {
- HapticFeedback.mediumImpact();
- }
- // 触发刷新任务
- SchedulerBinding.instance
- .addPostFrameCallback((Duration timestamp) {
- refreshTask = widget.onRefresh()
- ..then((_) {
- if (mounted && !widget.enableControlFinishRefresh) {
- if (widget.enableInfiniteRefresh) {
- refreshState = RefreshMode.inactive;
- }
- setState(() => refreshTask = null);
- if (!widget.enableInfiniteRefresh)
- refreshState = transitionNextState();
- }
- });
- });
- return RefreshMode.armed;
- }
- return RefreshMode.drag;
- }
- return RefreshMode.drag;
- }
- // Don't continue here. We can never possibly call onRefresh and
- // progress to the next state in one [computeNextState] call.
- break;
- case RefreshMode.armed:
- if (refreshState == RefreshMode.armed && !hasTask) {
- // 完成
- var state = goToFinish();
- if (state != null) return state;
- continue done;
- }
- if (latestIndicatorBoxExtent != widget.refreshIndicatorExtent) {
- return RefreshMode.armed;
- } else {
- nextState = RefreshMode.refresh;
- }
- continue refresh;
- refresh:
- case RefreshMode.refresh:
- if (refreshTask != null) {
- return RefreshMode.refresh;
- } else {
- // 完成
- var state = goToFinish();
- if (state != null) return state;
- }
- continue done;
- done:
- case RefreshMode.done:
- // Let the transition back to inactive trigger before strictly going
- // to 0.0 since the last bit of the animation can take some time and
- // can feel sluggish if not going all the way back to 0.0 prevented
- // a subsequent pull-to-refresh from starting.
- if (latestIndicatorBoxExtent >
- widget.refreshTriggerPullDistance *
- _inactiveResetOverscrollFraction) {
- return RefreshMode.done;
- } else {
- nextState = RefreshMode.inactive;
- }
- break;
- case RefreshMode.refreshed:
- nextState = refreshState;
- break;
- default:
- break;
- }
- return nextState;
- }
- @override
- Widget build(BuildContext context) {
- return _SliverRefresh(
- refreshIndicatorLayoutExtent: widget.refreshIndicatorExtent,
- hasLayoutExtent: hasSliverLayoutExtent,
- enableInfiniteRefresh: widget.enableInfiniteRefresh,
- infiniteRefresh: _infiniteRefresh,
- headerFloat: widget.headerFloat,
- axisDirectionNotifier: _axisDirectionNotifier,
- // A LayoutBuilder lets the sliver's layout changes be fed back out to
- // its owner to trigger state changes.
- child: LayoutBuilder(
- builder: (BuildContext context, BoxConstraints constraints) {
- // 判断是否有加载任务
- if (!widget.taskIndependence && widget.taskNotifier.value.loading) {
- return SizedBox();
- }
- // 是否为垂直方向
- bool isVertical =
- _axisDirectionNotifier.value == AxisDirection.down ||
- _axisDirectionNotifier.value == AxisDirection.up;
- latestIndicatorBoxExtent =
- isVertical ? constraints.maxHeight : constraints.maxWidth;
- refreshState = transitionNextState();
- if (widget.builder != null && latestIndicatorBoxExtent >= 0) {
- return widget.builder(
- context,
- refreshState,
- latestIndicatorBoxExtent,
- widget.refreshTriggerPullDistance,
- widget.refreshIndicatorExtent,
- _axisDirectionNotifier.value,
- widget.headerFloat,
- widget.completeDuration,
- widget.enableInfiniteRefresh,
- _success ?? true,
- _noMore ?? false,
- );
- }
- return Container();
- },
- ),
- );
- }
- }
|