material_header.dart 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import 'dart:async';
  2. import 'package:eye_video/framework/uikit/refresher/indicator/core/abstract_header.dart';
  3. import 'package:eye_video/framework/uikit/refresher/indicator/core/header_link_notifier.dart';
  4. import 'package:eye_video/framework/uikit/refresher/sliver/sliver_refresh.dart';
  5. import 'package:flutter/material.dart';
  6. const Duration _kIndicatorScaleDuration = Duration(milliseconds: 200);
  7. class MaterialHeader extends Header {
  8. final Key key;
  9. final double displacement;
  10. // 颜色
  11. final Animation<Color> valueColor;
  12. // 背景颜色
  13. final Color backgroundColor;
  14. final LinkHeaderNotifier linkNotifier = LinkHeaderNotifier();
  15. MaterialHeader({
  16. this.key,
  17. this.displacement = 40.0,
  18. this.valueColor,
  19. this.backgroundColor,
  20. completeDuration = const Duration(seconds: 1),
  21. bool enableHapticFeedback = false,
  22. }) : super(
  23. float: true,
  24. extent: 70.0,
  25. triggerDistance: 70.0,
  26. completeDuration: completeDuration == null
  27. ? Duration(
  28. milliseconds: 150,
  29. )
  30. : completeDuration +
  31. Duration(
  32. milliseconds: 150,
  33. ),
  34. enableInfiniteRefresh: false,
  35. enableHapticFeedback: enableHapticFeedback,
  36. );
  37. @override
  38. Widget contentBuilder(
  39. BuildContext context,
  40. RefreshMode refreshState,
  41. double pulledExtent,
  42. double refreshTriggerPullDistance,
  43. double refreshIndicatorExtent,
  44. AxisDirection axisDirection,
  45. bool float,
  46. Duration completeDuration,
  47. bool enableInfiniteRefresh,
  48. bool success,
  49. bool noMore) {
  50. linkNotifier.contentBuilder(
  51. context,
  52. refreshState,
  53. pulledExtent,
  54. refreshTriggerPullDistance,
  55. refreshIndicatorExtent,
  56. axisDirection,
  57. float,
  58. completeDuration,
  59. enableInfiniteRefresh,
  60. success,
  61. noMore);
  62. return MaterialHeaderWidget(
  63. key: key,
  64. displacement: displacement,
  65. valueColor: valueColor,
  66. backgroundColor: backgroundColor,
  67. linkNotifier: linkNotifier,
  68. );
  69. }
  70. }
  71. // 质感设计Header组件
  72. class MaterialHeaderWidget extends StatefulWidget {
  73. final double displacement;
  74. // 颜色
  75. final Animation<Color> valueColor;
  76. // 背景颜色
  77. final Color backgroundColor;
  78. final LinkHeaderNotifier linkNotifier;
  79. const MaterialHeaderWidget({
  80. Key key,
  81. this.displacement,
  82. this.valueColor,
  83. this.backgroundColor,
  84. this.linkNotifier,
  85. }) : super(key: key);
  86. @override
  87. MaterialHeaderWidgetState createState() {
  88. return MaterialHeaderWidgetState();
  89. }
  90. }
  91. class MaterialHeaderWidgetState extends State<MaterialHeaderWidget>
  92. with TickerProviderStateMixin<MaterialHeaderWidget> {
  93. static final Animatable<double> _oneToZeroTween =
  94. Tween<double>(begin: 1.0, end: 0.0);
  95. RefreshMode get _refreshState => widget.linkNotifier.refreshState;
  96. double get _pulledExtent => widget.linkNotifier.pulledExtent;
  97. double get _riggerPullDistance =>
  98. widget.linkNotifier.refreshTriggerPullDistance;
  99. Duration get _completeDuration => widget.linkNotifier.completeDuration;
  100. AxisDirection get _axisDirection => widget.linkNotifier.axisDirection;
  101. bool get _noMore => widget.linkNotifier.noMore;
  102. // 动画
  103. AnimationController _scaleController;
  104. Animation<double> _scaleFactor;
  105. @override
  106. void initState() {
  107. super.initState();
  108. _scaleController = AnimationController(vsync: this);
  109. _scaleFactor = _scaleController.drive(_oneToZeroTween);
  110. }
  111. @override
  112. void dispose() {
  113. _scaleController.dispose();
  114. super.dispose();
  115. }
  116. // 是否刷新完成
  117. bool _refreshFinish = false;
  118. set refreshFinish(bool finish) {
  119. if (_refreshFinish != finish) {
  120. if (finish) {
  121. Future.delayed(_completeDuration - Duration(milliseconds: 300), () {
  122. if (mounted) {
  123. _scaleController.animateTo(1.0, duration: _kIndicatorScaleDuration);
  124. }
  125. });
  126. Future.delayed(_completeDuration, () {
  127. if (mounted) {
  128. _refreshFinish = false;
  129. _scaleController.animateTo(0.0,
  130. duration: Duration(milliseconds: 10));
  131. }
  132. });
  133. }
  134. _refreshFinish = finish;
  135. }
  136. }
  137. @override
  138. Widget build(BuildContext context) {
  139. if (_noMore) return Container();
  140. // 是否为垂直方向
  141. bool isVertical = _axisDirection == AxisDirection.down ||
  142. _axisDirection == AxisDirection.up;
  143. // 是否反向
  144. bool isReverse = _axisDirection == AxisDirection.up ||
  145. _axisDirection == AxisDirection.left;
  146. // 计算进度值
  147. double indicatorValue = _pulledExtent / _riggerPullDistance;
  148. indicatorValue = indicatorValue < 1.0 ? indicatorValue : 1.0;
  149. // 判断是否刷新结束
  150. if (_refreshState == RefreshMode.refreshed) {
  151. refreshFinish = true;
  152. }
  153. return Container(
  154. height: isVertical
  155. ? _refreshState == RefreshMode.inactive ? 0.0 : _pulledExtent
  156. : double.infinity,
  157. width: !isVertical
  158. ? _refreshState == RefreshMode.inactive ? 0.0 : _pulledExtent
  159. : double.infinity,
  160. child: Stack(
  161. children: [
  162. Positioned(
  163. top: isVertical ? isReverse ? 0.0 : null : 0.0,
  164. bottom: isVertical ? !isReverse ? 0.0 : null : 0.0,
  165. left: !isVertical ? isReverse ? 0.0 : null : 0.0,
  166. right: !isVertical ? !isReverse ? 0.0 : null : 0.0,
  167. child: Container(
  168. padding: EdgeInsets.only(
  169. top: isVertical ? isReverse ? 0.0 : widget.displacement : 0.0,
  170. bottom:
  171. isVertical ? !isReverse ? 0.0 : widget.displacement : 0.0,
  172. left: !isVertical ? isReverse ? 0.0 : widget.displacement : 0.0,
  173. right:
  174. !isVertical ? !isReverse ? 0.0 : widget.displacement : 0.0,
  175. ),
  176. alignment: isVertical
  177. ? isReverse ? Alignment.topCenter : Alignment.bottomCenter
  178. : isReverse ? Alignment.centerLeft : Alignment.centerRight,
  179. child: ScaleTransition(
  180. scale: _scaleFactor,
  181. child: RefreshProgressIndicator(
  182. value: _refreshState == RefreshMode.armed ||
  183. _refreshState == RefreshMode.refresh ||
  184. _refreshState == RefreshMode.refreshed ||
  185. _refreshState == RefreshMode.done
  186. ? null
  187. : indicatorValue,
  188. valueColor: widget.valueColor,
  189. backgroundColor: widget.backgroundColor,
  190. ),
  191. ),
  192. ),
  193. ),
  194. ],
  195. ),
  196. );
  197. }
  198. }