add custom icon rotate widget

This commit is contained in:
julian 2023-02-27 17:51:22 -06:00
parent e3dbc64f17
commit 658708da95
3 changed files with 115 additions and 18 deletions

View file

@ -6,6 +6,7 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/animated_widgets/rotate_icon.dart';
import 'package:stackwallet/widgets/expandable.dart';
class ExpandingSubListItem extends StatefulWidget {
@ -14,11 +15,17 @@ class ExpandingSubListItem extends StatefulWidget {
required this.title,
required this.entities,
required this.initialState,
}) : super(key: key);
double? animationDurationMultiplier,
this.curve = Curves.easeInOutCubicEmphasized,
}) : animationDurationMultiplier =
animationDurationMultiplier ?? entities.length * 0.11,
super(key: key);
final String title;
final List<AddWalletListEntity> entities;
final ExpandableState initialState;
final double animationDurationMultiplier;
final Curve curve;
@override
State<ExpandingSubListItem> createState() => _ExpandingSubListItemState();
@ -28,31 +35,40 @@ class _ExpandingSubListItemState extends State<ExpandingSubListItem> {
final isDesktop = Util.isDesktop;
late final ExpandableController _controller;
late bool _expandedState;
late final RotateIconController _rotateIconController;
@override
void initState() {
_expandedState = widget.initialState == ExpandableState.expanded;
_controller = ExpandableController();
_rotateIconController = RotateIconController();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (_expandedState) {
if (widget.initialState == ExpandableState.expanded) {
_controller.toggle?.call();
}
});
super.initState();
}
@override
void dispose() {
_controller.toggle = null;
_rotateIconController.forward = null;
_rotateIconController.reverse = null;
super.dispose();
}
@override
Widget build(BuildContext context) {
return Expandable(
animationDurationMultiplier: 0.1 * widget.entities.length,
curve: Curves.easeInOutCubicEmphasized,
animationDurationMultiplier: widget.animationDurationMultiplier,
curve: widget.curve,
controller: _controller,
onExpandChanged: (state) {
setState(() {
_expandedState = state == ExpandableState.expanded;
});
onExpandWillChange: (state) {
if (state == ExpandableState.expanded) {
_rotateIconController.forward?.call();
} else {
_rotateIconController.reverse?.call();
}
},
header: Container(
color: Colors.transparent,
@ -76,13 +92,18 @@ class _ExpandingSubListItemState extends State<ExpandingSubListItem> {
: STextStyles.smallMed12(context),
textAlign: TextAlign.left,
),
SvgPicture.asset(
_expandedState ? Assets.svg.chevronUp : Assets.svg.chevronDown,
width: 12,
height: 6,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
RotateIcon(
icon: SvgPicture.asset(
Assets.svg.chevronDown,
width: 12,
height: 6,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
curve: widget.curve,
animationDurationMultiplier: widget.animationDurationMultiplier,
controller: _rotateIconController,
),
],
),

View file

@ -0,0 +1,72 @@
import 'package:flutter/widgets.dart';
class RotateIconController {
VoidCallback? forward;
VoidCallback? reverse;
}
class RotateIcon extends StatefulWidget {
const RotateIcon({
Key? key,
required this.icon,
required this.curve,
this.controller,
this.animationDurationMultiplier = 1.0,
this.rotationPercent = 0.5,
}) : super(key: key);
final Widget icon;
final Curve curve;
final RotateIconController? controller;
final double animationDurationMultiplier;
final double rotationPercent;
@override
State<RotateIcon> createState() => _RotateIconState();
}
class _RotateIconState extends State<RotateIcon>
with SingleTickerProviderStateMixin {
late final AnimationController animationController;
late final Animation<double> animation;
late final Duration duration;
@override
void initState() {
duration = Duration(
milliseconds: (500 * widget.animationDurationMultiplier).toInt(),
);
animationController = AnimationController(
vsync: this,
duration: duration,
);
animation = Tween<double>(
begin: 0.0,
end: widget.rotationPercent,
).animate(
CurvedAnimation(
curve: widget.curve,
parent: animationController,
),
);
widget.controller?.forward = animationController.forward;
widget.controller?.reverse = animationController.reverse;
super.initState();
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return RotationTransition(
turns: animation,
child: widget.icon,
);
}
}

View file

@ -19,6 +19,7 @@ class Expandable extends StatefulWidget {
this.animation,
this.animationDurationMultiplier = 1.0,
this.onExpandChanged,
this.onExpandWillChange,
this.controller,
this.expandOverride,
this.curve = Curves.easeInOut,
@ -30,6 +31,7 @@ class Expandable extends StatefulWidget {
final Animation<double>? animation;
final double animationDurationMultiplier;
final void Function(ExpandableState)? onExpandChanged;
final void Function(ExpandableState)? onExpandWillChange;
final ExpandableController? controller;
final VoidCallback? expandOverride;
final Curve curve;
@ -48,10 +50,12 @@ class _ExpandableState extends State<Expandable> with TickerProviderStateMixin {
Future<void> toggle() async {
if (animation.isDismissed) {
widget.onExpandWillChange?.call(ExpandableState.expanded);
await animationController.forward();
_toggleState = ExpandableState.expanded;
widget.onExpandChanged?.call(_toggleState);
} else if (animation.isCompleted) {
widget.onExpandWillChange?.call(ExpandableState.collapsed);
await animationController.reverse();
_toggleState = ExpandableState.collapsed;
widget.onExpandChanged?.call(_toggleState);