From 327578992ed17d197d18adb12cb5f2a098833447 Mon Sep 17 00:00:00 2001 From: codiss Date: Sun, 10 Jul 2022 22:49:43 +0800 Subject: [PATCH] feat: Add CupertinoIndicator. --- CHANGELOG.md | 3 +- example/lib/page/style/cupertino_page.dart | 89 +++++++++++++++++++ example/lib/page/style/style_page.dart | 7 ++ example/pubspec.yaml | 2 + lib/easy_refresh.dart | 4 + .../styles/bezier/footer/bezier_footer.dart | 2 +- .../bezier/header/bezier_circle_header.dart | 2 +- .../styles/bezier/header/bezier_header.dart | 2 +- .../styles/cupertino/cupertino_indicator.dart | 87 ++++++++++++++++++ .../cupertino/footer/cupertino_footer.dart | 47 ++++++++++ .../cupertino/header/cupertino_header.dart | 47 ++++++++++ .../delivery/footer/delivery_footer.dart | 2 +- .../delivery/header/delivery_header.dart | 2 +- .../material/footer/material_footer.dart | 2 +- .../material/header/material_header.dart | 2 +- .../styles/phoenix/footer/phoenix_footer.dart | 2 +- .../styles/phoenix/header/phoenix_header.dart | 2 +- .../styles/taurus/footer/taurus_footer.dart | 2 +- .../styles/taurus/header/taurus_header.dart | 2 +- 19 files changed, 296 insertions(+), 12 deletions(-) create mode 100644 example/lib/page/style/cupertino_page.dart create mode 100644 lib/src/styles/cupertino/cupertino_indicator.dart create mode 100644 lib/src/styles/cupertino/footer/cupertino_footer.dart create mode 100644 lib/src/styles/cupertino/header/cupertino_header.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 190393ec..2ca18848 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Change log ## Next -> fix: use notifyListeners after ChangeNotifier disposed. Thanks laiiihz for [PR#555](https://github.com/xuelongqy/flutter_easy_refresh/pull/555). +> fix: Use notifyListeners after ChangeNotifier disposed. Thanks laiiihz for [PR#555](https://github.com/xuelongqy/flutter_easy_refresh/pull/555). > feat: ClassicHeader、ClassicFooter add IconThemeData. Thanks Lay523 for [PR#562](https://github.com/xuelongqy/flutter_easy_refresh/pull/562). > feat: ClassicIndicator add [progressIndicatorSize] and [progressIndicatorStrokeWidth]. +> feat: Add CupertinoIndicator. ## V 3.0.0+3 > fix: dart >=2.13.0. diff --git a/example/lib/page/style/cupertino_page.dart b/example/lib/page/style/cupertino_page.dart new file mode 100644 index 00000000..159668b4 --- /dev/null +++ b/example/lib/page/style/cupertino_page.dart @@ -0,0 +1,89 @@ +import 'package:easy_refresh/easy_refresh.dart'; +import 'package:example/widget/skeleton_item.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CupertinoIndicatorPage extends StatefulWidget { + const CupertinoIndicatorPage({Key? key}) : super(key: key); + + @override + State createState() => _CupertinoIndicatorPageState(); +} + +class _CupertinoIndicatorPageState extends State { + int _count = 10; + late EasyRefreshController _controller; + + @override + void initState() { + super.initState(); + _controller = EasyRefreshController( + controlFinishRefresh: true, + controlFinishLoad: true, + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Material( + child: CupertinoPageScaffold( + child: EasyRefresh( + controller: _controller, + header: const CupertinoHeader( + position: IndicatorPosition.locator, + safeArea: false, + ), + footer: const CupertinoFooter( + position: IndicatorPosition.locator, + ), + onRefresh: () async { + await Future.delayed(const Duration(seconds: 2)); + if (!mounted) { + return; + } + setState(() { + _count = 10; + }); + _controller.finishRefresh(); + _controller.resetFooter(); + }, + onLoad: () async { + await Future.delayed(const Duration(seconds: 2)); + if (!mounted) { + return; + } + setState(() { + _count += 5; + }); + _controller.finishLoad(_count >= 20 + ? IndicatorResult.noMore + : IndicatorResult.success); + }, + child: CustomScrollView( + slivers: [ + const CupertinoSliverNavigationBar( + largeTitle: Text('iOS Cupertino'), + ), + const HeaderLocator.sliver(), + SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return const SkeletonItem(); + }, + childCount: _count, + ), + ), + const FooterLocator.sliver(), + ], + ), + ), + ), + ); + } +} diff --git a/example/lib/page/style/style_page.dart b/example/lib/page/style/style_page.dart index 5e7cd1e9..0164feb0 100644 --- a/example/lib/page/style/style_page.dart +++ b/example/lib/page/style/style_page.dart @@ -1,6 +1,7 @@ import 'package:example/page/style/bezier_circle_page.dart'; import 'package:example/page/style/bezier_page.dart'; import 'package:example/page/style/classical_page.dart'; +import 'package:example/page/style/cupertino_page.dart'; import 'package:example/page/style/delivery_page.dart'; import 'package:example/page/style/halloween_page.dart'; import 'package:example/page/style/material_page.dart'; @@ -52,6 +53,12 @@ class _StylePageState extends State { icon: Icons.refresh, onTap: () => Get.to(() => const MaterialIndicatorPage()), ), + ListItem( + title: 'Cupertino', + subtitle: 'iOS Cupertino', + icon: Icons.apple, + onTap: () => Get.to(() => const CupertinoIndicatorPage()), + ), ListItem( title: 'Bezier', subtitle: 'Bezier curve'.tr, diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 3b9615ec..ce1526fc 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -19,6 +19,8 @@ dependencies: flutter_localizations: sdk: flutter + cupertino_icons: ^1.0.5 + url_launcher: ^6.1.4 flutter_spinkit: ^5.1.0 flare_flutter: ^3.0.2 diff --git a/lib/easy_refresh.dart b/lib/easy_refresh.dart index 39375762..14927788 100644 --- a/lib/easy_refresh.dart +++ b/lib/easy_refresh.dart @@ -3,6 +3,7 @@ library easy_refresh; import 'dart:math' as math; import 'dart:async'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -43,3 +44,6 @@ part 'src/styles/taurus/footer/taurus_footer.dart'; part 'src/styles/delivery/delivery_indicator.dart'; part 'src/styles/delivery/header/delivery_header.dart'; part 'src/styles/delivery/footer/delivery_footer.dart'; +part 'src/styles/cupertino/cupertino_indicator.dart'; +part 'src/styles/cupertino/header/cupertino_header.dart'; +part 'src/styles/cupertino/footer/cupertino_footer.dart'; diff --git a/lib/src/styles/bezier/footer/bezier_footer.dart b/lib/src/styles/bezier/footer/bezier_footer.dart index 9be393b8..ae0e152d 100644 --- a/lib/src/styles/bezier/footer/bezier_footer.dart +++ b/lib/src/styles/bezier/footer/bezier_footer.dart @@ -22,7 +22,7 @@ class BezierFooter extends Footer { /// Background color. final Color? backgroundColor; - BezierFooter({ + const BezierFooter({ this.key, double triggerOffset = 100, bool clamping = false, diff --git a/lib/src/styles/bezier/header/bezier_circle_header.dart b/lib/src/styles/bezier/header/bezier_circle_header.dart index 44bea2b9..72367220 100644 --- a/lib/src/styles/bezier/header/bezier_circle_header.dart +++ b/lib/src/styles/bezier/header/bezier_circle_header.dart @@ -10,7 +10,7 @@ class BezierCircleHeader extends Header { /// Background color. final Color? backgroundColor; - BezierCircleHeader({ + const BezierCircleHeader({ this.key, double triggerOffset = 100, bool clamping = false, diff --git a/lib/src/styles/bezier/header/bezier_header.dart b/lib/src/styles/bezier/header/bezier_header.dart index c5ea1e92..a0a6e642 100644 --- a/lib/src/styles/bezier/header/bezier_header.dart +++ b/lib/src/styles/bezier/header/bezier_header.dart @@ -22,7 +22,7 @@ class BezierHeader extends Header { /// Background color. final Color? backgroundColor; - BezierHeader({ + const BezierHeader({ this.key, double triggerOffset = 100, bool clamping = false, diff --git a/lib/src/styles/cupertino/cupertino_indicator.dart b/lib/src/styles/cupertino/cupertino_indicator.dart new file mode 100644 index 00000000..7a5c7b1f --- /dev/null +++ b/lib/src/styles/cupertino/cupertino_indicator.dart @@ -0,0 +1,87 @@ +part of easy_refresh; + +const double _kDefaultCupertinoIndicatorRadius = 14.0; + +/// Cupertino indicator. +/// Base widget for [CupertinoHeader] and [CupertinoFooter]. +class _CupertinoIndicator extends StatefulWidget { + /// Indicator properties and state. + final IndicatorState state; + + /// True for up and left. + /// False for down and right. + final bool reverse; + + const _CupertinoIndicator({ + Key? key, + required this.state, + required this.reverse, + }) : super(key: key); + + @override + State<_CupertinoIndicator> createState() => _CupertinoIndicatorState(); +} + +class _CupertinoIndicatorState extends State<_CupertinoIndicator> { + IndicatorMode get _mode => widget.state.mode; + double get _offset => widget.state.offset; + double get _actualTriggerOffset => widget.state.actualTriggerOffset; + + double get _radius => _kDefaultCupertinoIndicatorRadius; + + Widget _buildIndicator() { + final scale = (_offset / _actualTriggerOffset).clamp(0.0, 1.0); + switch (_mode) { + case IndicatorMode.drag: + case IndicatorMode.armed: + const Curve opacityCurve = Interval( + 0.0, + 0.8, + curve: Curves.easeInOut, + ); + return Opacity( + opacity: opacityCurve.transform(scale), + child: CupertinoActivityIndicator.partiallyRevealed( + radius: _radius, + progress: math.min(scale, 0.99), + ), + ); + case IndicatorMode.ready: + case IndicatorMode.processing: + case IndicatorMode.processed: + return CupertinoActivityIndicator( + radius: _radius, + ); + case IndicatorMode.done: + return CupertinoActivityIndicator( + radius: _radius * scale, + ); + default: + return Container(); + } + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + SizedBox( + height: _offset, + width: double.infinity, + ), + Positioned( + top: 0, + left: 0, + right: 0, + child: Container( + alignment: Alignment.center, + height: _actualTriggerOffset, + width: double.infinity, + child: _buildIndicator(), + ), + ), + ], + ); + } +} diff --git a/lib/src/styles/cupertino/footer/cupertino_footer.dart b/lib/src/styles/cupertino/footer/cupertino_footer.dart new file mode 100644 index 00000000..fe069a1f --- /dev/null +++ b/lib/src/styles/cupertino/footer/cupertino_footer.dart @@ -0,0 +1,47 @@ +part of easy_refresh; + +class CupertinoFooter extends Footer { + final Key? key; + + const CupertinoFooter({ + this.key, + double triggerOffset = 60, + bool clamping = false, + IndicatorPosition position = IndicatorPosition.behind, + Duration processedDuration = Duration.zero, + SpringDescription? spring, + SpringBuilder? readySpringBuilder, + bool springRebound = true, + FrictionFactor? frictionFactor, + bool safeArea = true, + double? infiniteOffset = 60, + bool? hitOver, + bool? infiniteHitOver, + bool hapticFeedback = false, + }) : super( + triggerOffset: triggerOffset, + clamping: clamping, + processedDuration: processedDuration, + spring: spring, + readySpringBuilder: readySpringBuilder, + springRebound: springRebound, + frictionFactor: frictionFactor, + safeArea: safeArea, + infiniteOffset: infiniteOffset, + hitOver: hitOver, + infiniteHitOver: infiniteHitOver, + position: position, + hapticFeedback: hapticFeedback, + ); + + @override + Widget build(BuildContext context, IndicatorState state) { + assert(state.axis == Axis.vertical, + 'CupertinoFooter does not support horizontal scrolling.'); + return _CupertinoIndicator( + key: key, + state: state, + reverse: state.reverse, + ); + } +} diff --git a/lib/src/styles/cupertino/header/cupertino_header.dart b/lib/src/styles/cupertino/header/cupertino_header.dart new file mode 100644 index 00000000..f0eb379c --- /dev/null +++ b/lib/src/styles/cupertino/header/cupertino_header.dart @@ -0,0 +1,47 @@ +part of easy_refresh; + +class CupertinoHeader extends Header { + final Key? key; + + const CupertinoHeader({ + this.key, + double triggerOffset = 60, + bool clamping = false, + IndicatorPosition position = IndicatorPosition.behind, + Duration processedDuration = const Duration(seconds: 1), + SpringDescription? spring, + SpringBuilder? readySpringBuilder, + bool springRebound = false, + FrictionFactor? frictionFactor, + bool safeArea = true, + double? infiniteOffset, + bool? hitOver, + bool? infiniteHitOver, + bool hapticFeedback = false, + }) : super( + triggerOffset: triggerOffset, + clamping: clamping, + processedDuration: processedDuration, + spring: spring, + readySpringBuilder: readySpringBuilder, + springRebound: springRebound, + frictionFactor: frictionFactor, + safeArea: safeArea, + infiniteOffset: infiniteOffset, + hitOver: hitOver, + infiniteHitOver: infiniteHitOver, + position: position, + hapticFeedback: hapticFeedback, + ); + + @override + Widget build(BuildContext context, IndicatorState state) { + assert(state.axis == Axis.vertical, + 'CupertinoHeader does not support horizontal scrolling.'); + return _CupertinoIndicator( + key: key, + state: state, + reverse: state.reverse, + ); + } +} diff --git a/lib/src/styles/delivery/footer/delivery_footer.dart b/lib/src/styles/delivery/footer/delivery_footer.dart index 13b3399e..d6ee829d 100644 --- a/lib/src/styles/delivery/footer/delivery_footer.dart +++ b/lib/src/styles/delivery/footer/delivery_footer.dart @@ -6,7 +6,7 @@ class DeliveryFooter extends Footer { /// Sky color. final Color? skyColor; - DeliveryFooter({ + const DeliveryFooter({ this.key, double triggerOffset = kDeliveryTriggerOffset, bool clamping = false, diff --git a/lib/src/styles/delivery/header/delivery_header.dart b/lib/src/styles/delivery/header/delivery_header.dart index 02614f0c..8b743dc3 100644 --- a/lib/src/styles/delivery/header/delivery_header.dart +++ b/lib/src/styles/delivery/header/delivery_header.dart @@ -6,7 +6,7 @@ class DeliveryHeader extends Header { /// Sky color. final Color? skyColor; - DeliveryHeader({ + const DeliveryHeader({ this.key, double triggerOffset = kDeliveryTriggerOffset, bool clamping = false, diff --git a/lib/src/styles/material/footer/material_footer.dart b/lib/src/styles/material/footer/material_footer.dart index c3a102d4..b61fa1ce 100644 --- a/lib/src/styles/material/footer/material_footer.dart +++ b/lib/src/styles/material/footer/material_footer.dart @@ -37,7 +37,7 @@ class MaterialFooter extends Footer { /// See [BezierBackground.bounce]. final bool bezierBackgroundBounce; - MaterialFooter({ + const MaterialFooter({ this.key, double triggerOffset = 100, bool clamping = true, diff --git a/lib/src/styles/material/header/material_header.dart b/lib/src/styles/material/header/material_header.dart index d6d8862d..6aeb27fa 100644 --- a/lib/src/styles/material/header/material_header.dart +++ b/lib/src/styles/material/header/material_header.dart @@ -37,7 +37,7 @@ class MaterialHeader extends Header { /// See [BezierBackground.bounce]. final bool bezierBackgroundBounce; - MaterialHeader({ + const MaterialHeader({ this.key, double triggerOffset = 100, bool clamping = true, diff --git a/lib/src/styles/phoenix/footer/phoenix_footer.dart b/lib/src/styles/phoenix/footer/phoenix_footer.dart index 7a17361b..e73000e1 100644 --- a/lib/src/styles/phoenix/footer/phoenix_footer.dart +++ b/lib/src/styles/phoenix/footer/phoenix_footer.dart @@ -6,7 +6,7 @@ class PhoenixFooter extends Footer { /// Sky color. final Color? skyColor; - PhoenixFooter({ + const PhoenixFooter({ this.key, double triggerOffset = 100, bool clamping = false, diff --git a/lib/src/styles/phoenix/header/phoenix_header.dart b/lib/src/styles/phoenix/header/phoenix_header.dart index 9c6ccc12..02b341fa 100644 --- a/lib/src/styles/phoenix/header/phoenix_header.dart +++ b/lib/src/styles/phoenix/header/phoenix_header.dart @@ -6,7 +6,7 @@ class PhoenixHeader extends Header { /// Sky color. final Color? skyColor; - PhoenixHeader({ + const PhoenixHeader({ this.key, double triggerOffset = 100, bool clamping = false, diff --git a/lib/src/styles/taurus/footer/taurus_footer.dart b/lib/src/styles/taurus/footer/taurus_footer.dart index e5ffb99c..17f1a5eb 100644 --- a/lib/src/styles/taurus/footer/taurus_footer.dart +++ b/lib/src/styles/taurus/footer/taurus_footer.dart @@ -6,7 +6,7 @@ class TaurusFooter extends Footer { /// Sky color. final Color? skyColor; - TaurusFooter({ + const TaurusFooter({ this.key, double triggerOffset = 100, bool clamping = false, diff --git a/lib/src/styles/taurus/header/taurus_header.dart b/lib/src/styles/taurus/header/taurus_header.dart index e2785a23..1f265cfd 100644 --- a/lib/src/styles/taurus/header/taurus_header.dart +++ b/lib/src/styles/taurus/header/taurus_header.dart @@ -6,7 +6,7 @@ class TaurusHeader extends Header { /// Sky color. final Color? skyColor; - TaurusHeader({ + const TaurusHeader({ this.key, double triggerOffset = 100, bool clamping = false,