Files
DMZJ_F/lib/widgets/custom_header.dart
2026-03-07 17:24:59 +08:00

440 lines
13 KiB
Dart

import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart' as physics;
import 'dart:math' as math;
/// Material header.
class MaterialHeader2 extends Header {
final Key? key;
/// See [ProgressIndicator.backgroundColor].
final Color? backgroundColor;
/// See [ProgressIndicator.color].
final Color? color;
/// See [ProgressIndicator.valueColor].
final Animation<Color?>? valueColor;
/// See [ProgressIndicator.semanticsLabel].
final String? semanticsLabel;
/// See [ProgressIndicator.semanticsLabel].
final String? semanticsValue;
/// Icon when [IndicatorResult.noMore].
final Widget? noMoreIcon;
/// Show bezier background.
final bool showBezierBackground;
/// Bezier background color.
/// See [BezierBackground.color].
final Color? bezierBackgroundColor;
/// Bezier background animation.
/// See [BezierBackground.useAnimation].
final bool bezierBackgroundAnimation;
/// Bezier background bounce.
/// See [BezierBackground.bounce].
final bool bezierBackgroundBounce;
final Widget child;
const MaterialHeader2({
this.key,
double triggerOffset = 100,
bool clamping = true,
IndicatorPosition position = IndicatorPosition.above,
Duration processedDuration = const Duration(milliseconds: 200),
physics.SpringDescription? spring,
bool springRebound = false,
SpringBuilder? readySpringBuilder,
FrictionFactor? frictionFactor,
bool safeArea = true,
double? infiniteOffset,
bool? hitOver,
bool? infiniteHitOver,
bool hapticFeedback = false,
bool triggerWhenRelease = false,
double maxOverOffset = double.infinity,
required this.child,
this.backgroundColor,
this.color,
this.valueColor,
this.semanticsLabel,
this.semanticsValue,
this.noMoreIcon,
this.showBezierBackground = false,
this.bezierBackgroundColor,
this.bezierBackgroundAnimation = false,
this.bezierBackgroundBounce = false,
}) : super(
triggerOffset: triggerOffset,
clamping: clamping,
processedDuration: processedDuration,
spring: spring,
readySpringBuilder: readySpringBuilder ??
(bezierBackgroundAnimation
? kBezierSpringBuilder
: kMaterialSpringBuilder),
springRebound: springRebound,
frictionFactor: frictionFactor ??
(showBezierBackground
? kBezierFrictionFactor
: kMaterialFrictionFactor),
horizontalFrictionFactor: frictionFactor ??
(showBezierBackground
? kBezierHorizontalFrictionFactor
: kMaterialHorizontalFrictionFactor),
safeArea: safeArea,
infiniteOffset: infiniteOffset,
hitOver: hitOver,
infiniteHitOver: infiniteHitOver,
position: position,
hapticFeedback: hapticFeedback,
triggerWhenRelease: triggerWhenRelease,
maxOverOffset: maxOverOffset,
);
@override
Widget build(BuildContext context, IndicatorState state) {
return _MaterialIndicator(
key: key,
state: state,
disappearDuration: processedDuration,
reverse: state.reverse,
backgroundColor: backgroundColor,
color: color,
valueColor: valueColor,
semanticsLabel: semanticsLabel,
semanticsValue: semanticsValue,
noMoreIcon: noMoreIcon,
showBezierBackground: showBezierBackground,
bezierBackgroundColor: bezierBackgroundColor,
bezierBackgroundAnimation: bezierBackgroundAnimation,
bezierBackgroundBounce: bezierBackgroundBounce,
child: child,
);
}
}
class MaterialFooter2 extends Footer {
final Key? key;
/// See [ProgressIndicator.backgroundColor].
final Color? backgroundColor;
/// See [ProgressIndicator.color].
final Color? color;
/// See [ProgressIndicator.valueColor].
final Animation<Color?>? valueColor;
/// See [ProgressIndicator.semanticsLabel].
final String? semanticsLabel;
/// See [ProgressIndicator.semanticsLabel].
final String? semanticsValue;
/// Icon when [IndicatorResult.noMore].
final Widget? noMoreIcon;
/// Show bezier background.
final bool showBezierBackground;
/// Bezier background color.
/// See [BezierBackground.color].
final Color? bezierBackgroundColor;
/// Bezier background animation.
/// See [BezierBackground.useAnimation].
final bool bezierBackgroundAnimation;
/// Bezier background bounce.
/// See [BezierBackground.bounce].
final bool bezierBackgroundBounce;
final Widget child;
const MaterialFooter2({
this.key,
double triggerOffset = 100,
bool clamping = true,
IndicatorPosition position = IndicatorPosition.above,
Duration processedDuration = const Duration(milliseconds: 200),
physics.SpringDescription? spring,
SpringBuilder? readySpringBuilder,
bool springRebound = false,
FrictionFactor? frictionFactor,
bool safeArea = true,
double? infiniteOffset,
bool? hitOver,
bool? infiniteHitOver,
bool hapticFeedback = false,
bool triggerWhenRelease = false,
double maxOverOffset = double.infinity,
required this.child,
this.backgroundColor,
this.color,
this.valueColor,
this.semanticsLabel,
this.semanticsValue,
this.noMoreIcon,
this.showBezierBackground = false,
this.bezierBackgroundColor,
this.bezierBackgroundAnimation = false,
this.bezierBackgroundBounce = false,
}) : super(
triggerOffset: triggerOffset,
clamping: clamping,
processedDuration: processedDuration,
spring: spring,
readySpringBuilder: readySpringBuilder ??
(bezierBackgroundAnimation
? kBezierSpringBuilder
: kMaterialSpringBuilder),
springRebound: springRebound,
frictionFactor: frictionFactor ??
(showBezierBackground
? kBezierFrictionFactor
: kMaterialFrictionFactor),
horizontalFrictionFactor: frictionFactor ??
(showBezierBackground
? kBezierHorizontalFrictionFactor
: kMaterialHorizontalFrictionFactor),
safeArea: safeArea,
infiniteOffset: infiniteOffset,
hitOver: hitOver,
infiniteHitOver: infiniteHitOver,
position: position,
hapticFeedback: hapticFeedback,
triggerWhenRelease: triggerWhenRelease,
maxOverOffset: maxOverOffset,
);
@override
Widget build(BuildContext context, IndicatorState state) {
return _MaterialIndicator(
key: key,
state: state,
disappearDuration: processedDuration,
reverse: !state.reverse,
backgroundColor: backgroundColor,
color: color,
valueColor: valueColor,
semanticsLabel: semanticsLabel,
semanticsValue: semanticsValue,
noMoreIcon: noMoreIcon,
showBezierBackground: showBezierBackground,
bezierBackgroundColor: bezierBackgroundColor,
bezierBackgroundAnimation: bezierBackgroundAnimation,
bezierBackgroundBounce: bezierBackgroundBounce,
child: child,
);
}
}
/// Material indicator.
/// Base widget for [MaterialHeader] and [MaterialFooter].
class _MaterialIndicator extends StatefulWidget {
/// Indicator properties and state.
final IndicatorState state;
/// See [ProgressIndicator.backgroundColor].
final Color? backgroundColor;
/// See [ProgressIndicator.color].
final Color? color;
/// See [ProgressIndicator.valueColor].
final Animation<Color?>? valueColor;
/// See [ProgressIndicator.semanticsLabel].
final String? semanticsLabel;
/// See [ProgressIndicator.semanticsLabel].
final String? semanticsValue;
/// Indicator disappears duration.
/// When the mode is [IndicatorMode.processed].
final Duration disappearDuration;
/// True for up and left.
/// False for down and right.
final bool reverse;
/// Icon when [IndicatorResult.noMore].
final Widget? noMoreIcon;
/// Show bezier background.
final bool showBezierBackground;
/// Bezier background color.
/// See [BezierBackground.color].
final Color? bezierBackgroundColor;
/// Bezier background animation.
/// See [BezierBackground.useAnimation].
final bool bezierBackgroundAnimation;
/// Bezier background bounce.
/// See [BezierBackground.bounce].
final bool bezierBackgroundBounce;
final Widget child;
const _MaterialIndicator({
Key? key,
required this.state,
required this.disappearDuration,
required this.reverse,
required this.child,
this.backgroundColor,
this.color,
this.valueColor,
this.semanticsLabel,
this.semanticsValue,
this.noMoreIcon,
this.showBezierBackground = false,
this.bezierBackgroundColor,
this.bezierBackgroundAnimation = false,
this.bezierBackgroundBounce = false,
}) : super(key: key);
@override
State<_MaterialIndicator> createState() => _MaterialIndicatorState();
}
/// See [ProgressIndicator] _kMinCircularProgressIndicatorSize.
const double _kCircularProgressIndicatorSize = 48;
/// Friction factor used by material.
double kMaterialFrictionFactor(double overscrollFraction) =>
0.875 * math.pow(1 - overscrollFraction, 2);
/// Friction factor used by material horizontal.
double kMaterialHorizontalFrictionFactor(double overscrollFraction) =>
1.0 * math.pow(1 - overscrollFraction, 2);
/// Spring description used by material.
physics.SpringDescription kMaterialSpringBuilder({
required IndicatorMode mode,
required double offset,
required double actualTriggerOffset,
required double velocity,
}) =>
physics.SpringDescription.withDampingRatio(
mass: 1,
stiffness: 500,
ratio: 1.1,
);
class _MaterialIndicatorState extends State<_MaterialIndicator> {
IndicatorMode get _mode => widget.state.mode;
IndicatorResult get _result => widget.state.result;
Axis get _axis => widget.state.axis;
double get _offset => widget.state.offset;
double get _actualTriggerOffset => widget.state.actualTriggerOffset;
/// Build [RefreshProgressIndicator].
Widget _buildIndicator() {
return Container(
alignment: _axis == Axis.vertical
? (widget.reverse ? Alignment.topCenter : Alignment.bottomCenter)
: (widget.reverse ? Alignment.centerLeft : Alignment.centerRight),
height: _axis == Axis.vertical ? _actualTriggerOffset : double.infinity,
width: _axis == Axis.horizontal ? _actualTriggerOffset : double.infinity,
child: Stack(
alignment: Alignment.center,
children: [
widget.child,
if (_mode == IndicatorMode.inactive &&
_result == IndicatorResult.noMore)
widget.noMoreIcon ?? const Icon(Icons.inbox_outlined),
],
),
);
}
@override
Widget build(BuildContext context) {
double offset = _offset;
if (widget.state.indicator.infiniteOffset != null &&
widget.state.indicator.position == IndicatorPosition.locator &&
(_mode != IndicatorMode.inactive ||
_result == IndicatorResult.noMore)) {
offset = _actualTriggerOffset;
}
final padding = math.max(_offset - _kCircularProgressIndicatorSize, 0) / 2;
return Stack(
clipBehavior: Clip.none,
children: [
SizedBox(
width: _axis == Axis.vertical ? double.infinity : offset,
height: _axis == Axis.horizontal ? double.infinity : offset,
),
if (widget.showBezierBackground)
Positioned(
top: _axis == Axis.vertical
? widget.reverse
? null
: 0
: 0,
left: _axis == Axis.horizontal
? widget.reverse
? null
: 0
: 0,
right: _axis == Axis.horizontal
? widget.reverse
? 0
: null
: 0,
bottom: _axis == Axis.vertical
? widget.reverse
? 0
: null
: 0,
child: BezierBackground(
state: widget.state,
color: widget.bezierBackgroundColor,
useAnimation: widget.bezierBackgroundAnimation,
bounce: widget.bezierBackgroundBounce,
reverse: widget.reverse,
),
),
Positioned(
top: _axis == Axis.vertical
? widget.reverse
? padding
: null
: 0,
bottom: _axis == Axis.vertical
? widget.reverse
? null
: padding
: 0,
left: _axis == Axis.horizontal
? widget.reverse
? padding
: null
: 0,
right: _axis == Axis.horizontal
? widget.reverse
? null
: padding
: 0,
child: Center(
child: _buildIndicator(),
),
),
],
);
}
}