Skip to content

Add VoidCallback to AnimatedSize (Similar to AnimatedOpacity's onEnd)  #106439

@Dall127

Description

@Dall127

Use case

I am using an implicit Animation widget and an explicit animating widget, and I would like to be able to add a listener to see when the implicit widget is done to then call my explicitly animated widget. In short, I would like the AnimatedSize to finish animating before changing the Opacity. And, not stopping there, I would like to be able to chain the animations for all implicitly animated widgets. Something along the lines of

AnimatedSize(
    onFinishAnimating: () { 
         driveExplicitAnimation();
         // or 
       
       setState(() { 
           setAnotherAnimatedWidgetsValue();
      });
    }
    child: Container()
);

Proposal

add callback/listener on implicitly animated widget to call explicitly animated widget when the implicitly animated widget is done animating.

Sample Code

Note: While the sample code does not have any explicitly animated widgets, it provides the two types of "desired" animations from the implicitly animated widgets. But, because there is nothing that allows me to snoop on their animations (diving into the code for Animated Size, it seems that the animation controller is private, not allowing me to user key.currentState.findRenderObject), thus is not allowing me to better chain animations. When I set the child of the expanded content, I would like the AnimatedSize to finish animating before changing the Opacity.

Details
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
 
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<int> rows = List.filled(5, 0);

  @override
  Widget build(BuildContext context) {

    return Scaffold(
        appBar: AppBar(

          title: Text(widget.title),
        ),
        body: ListView.builder(itemBuilder: ((context, index) {
          return AnimatingRow(rowNum: index, info: "Info at a glance");
        })));
  }
}

class AnimatingRow extends StatefulWidget {
  final int rowNum;
  final String info;

  const AnimatingRow({super.key, required this.rowNum, required this.info});

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

class AnimatingRowState extends State<AnimatingRow> {
  static const String _showMoreText = "Show More";
  static const String _showLessText = "Show Less";
  static const rowColor = Color.fromARGB(255, 235, 235, 235);
  static const fillerText =
      "asdfjaslkdfjlsdjkfalskdjfalasodifj;lasdfjlkasjfd;lkajsdfljkas;dflkjas;dlkfja;sldjfasldkjflasdjf;lsakjdfl;asjdflsdkjfal;sdjf;alsdjfk;lasdjf;lasjdf;lasjdfl;askjdfl;ajsdfjkasdf";
  late bool showingMore;
  late double childOpacity;
  late final int rowNum;
  late String _showText;

  Widget moreWidget = Container();
  @override
  void initState() {
    _showText = _showMoreText;
    showingMore = false;
    childOpacity = 0;
    rowNum = widget.rowNum;
    super.initState();
  }

  Color? getRowColor(int rowNumber) {
    if (rowNumber.isEven) {
      return rowColor;
    } else {
      return null;
    }
  }

  void showButtonPress() {
    if (showingMore) {
      setState(() {
        _showText = _showMoreText;
        showingMore = false;
        moreWidget = Container();
        childOpacity = 0;
      });
    } else {
      const exampleList = Text(fillerText);
      setState(() {
        _showText = _showLessText;
        showingMore = true;
        moreWidget = exampleList;
        childOpacity = 1;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedSize(
        duration: const Duration(milliseconds: 250),
        child: ColorBackground(
            backgroundColor: getRowColor(rowNum),
            margin: const EdgeInsets.only(
              left: 20,
              right: 20,
            ),
            child: Column(children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                textDirection: TextDirection.ltr,
                children: [
                  Text(widget.info),
                  Align(
                      alignment: Alignment.bottomRight,
                      child: TextButton(
                        onPressed: showButtonPress,
                        child: Text(_showText),
                      ))
                ],
              ),
              AnimatedOpacity(
                duration: const Duration(milliseconds: 250),
                opacity: childOpacity,
                child: moreWidget,
              )
            ])));
  }
}

class ColorBackground extends Container {
  final double radius;
  final double opacity;
  final MainAxisAlignment mainAxisAlignment;
  late final Color? backgroundColor;

  ColorBackground(
      {super.key,
      super.child,
      this.opacity = 1,
      super.width,
      super.height,
      super.constraints,
      this.backgroundColor = Colors.grey,
      this.radius = 10,
      this.mainAxisAlignment = MainAxisAlignment.center,
      super.padding = const EdgeInsets.all(15),
      super.margin});

  @override
  BoxDecoration get decoration {
    return BoxDecoration(
        color: backgroundColor?.withOpacity(opacity),
        borderRadius: BorderRadius.all(Radius.circular(radius)));
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Issues that are less important to the Flutter projecta: animationAnimation APIsc: proposalA detailed proposal for a change to Flutterframeworkflutter/packages/flutter repository. See also f: labels.r: fixedIssue is closed as already fixed in a newer versionteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions