Flutter SizeTransition only at first widget build

Viewed 110

I made a widget 'ExpandableSection' which animates the child content by using a SizeTransition. It also works fine so far but I would like to have an additional parameter like "disableAtFirstBuild" so there is no initial animation but the widget is instantly shown. And only on rebuild the animation should be triggered. It seems like an easy task but I searched multiple hours for a solution without luck. For example I tried to set the animation duration to zero at first, invert a state boolean to save the fact that one build is done and afterwards set the duration to the normal value again. But somehow you cannot change an active controller. Is there a way to do it? Maybe it is quite easy and obvious but it is just not clear to me.

Any help would be much appreciated.

import 'package:flutter/widgets.dart';

class ExpandableSection extends StatefulWidget {
 final Widget? child;
 final bool? expand, useSliverScrollSafeMode;
 final Axis axis;
 ExpandableSection({this.expand = false, this.useSliverScrollSafeMode = false, this.axis = Axis.vertical, this.child});

 @override
 _ExpandableSectionState createState() => _ExpandableSectionState();
}

class _ExpandableSectionState extends State<ExpandableSection> with SingleTickerProviderStateMixin {
 late AnimationController expandController;
 late Animation<double> animation;

 @override
 void initState() {
   super.initState();
   prepareAnimations();
   _runExpandCheck();
 }

 void prepareAnimations() {
   expandController = AnimationController(vsync: this, duration: const Duration(milliseconds: 650));
   animation = CurvedAnimation(
     parent: expandController,
     curve: Curves.easeInOutQuart,
   );
 }

 void _runExpandCheck() {
   if (widget.expand!) {
     expandController.forward();
   } else {
     expandController.reverse();
   }
 }

 @override
 void didUpdateWidget(ExpandableSection oldWidget) {
   super.didUpdateWidget(oldWidget);
   _runExpandCheck();
 }

 @override
 void dispose() {
   expandController.dispose();
   super.dispose();
 }

 @override
 Widget build(BuildContext context) {
   if (widget.useSliverScrollSafeMode! && !expandController.isAnimating && !widget.expand!) {
     return SizedBox.shrink();
   } else {
     return SizeTransition(axisAlignment: -1, axis: widget.axis, sizeFactor: animation, child: Center(child: widget.child));
   }
 }
}
2 Answers

Try stoping the animation controller in initState and then calling .forward() whenever you want it to run.

@override
 void initState() {
 super.initState();
 prepareAnimations();
 _runExpandCheck();
 expandController.stop();
}

Add 'value' to your controller while creating it; like this:

expandController = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 650),
    value: widget.expand ? 650 : 0,
);
Related