Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Flutter, how to solve `AnimatedCrossFade` inefficient design?

A problem with AnimatedCrossFade is that you must provide both children, even if only one of them is being displayed.

If one (or both) of those children is complex and heavy, this is not efficient.

I have tried to provide a Builder as a child, like this:

AnimatedCrossFade(
    firstChild: widget1,
    secondChild: Builder(builder: widget2builder),
    duration: const Duration(milliseconds: 500),
    crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),

var widget2builder = (context) {
  print("Building widget 2");
  return Container(),
  );
};

However, this prints Building widget 2 right away, even if the first widget is the one being displayed and thus widget 2 is not needed at all.

This is a complete, runnable example:

import 'package:flutter/material.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  bool toggle;

  @override
  void initState() {
    super.initState();
    toggle = true;
  }

  @override
  Widget build(BuildContext context) {
    var toggleButton = Padding(
      padding: const EdgeInsets.all(8.0),
      child: MaterialButton(
        child: const Text("Toggle"),
        color: Colors.grey,
        onPressed: () {
          setState(() {
            toggle = !toggle;
          });
        },
      ),
    );

    var widget1 = Container(
      key: UniqueKey(),
      color: Colors.blue,
      width: 200.0,
      child: const Text(
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt "
            "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
            "ullamco laboris nisi ut aliquip ex ea commodo consequat.",
      ),
    );

    var widget2builder = (context) {
      print("Building widget 2.");
      return Container(
        key: UniqueKey(),
        color: Colors.red,
        width: 200.0,
        child: const Text(
          "I am ready for my closeup.",
        ),
      );
    };

    return MaterialApp(
      home: Material(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            toggleButton,
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                const Text("Some text above."),
                AnimatedCrossFade(
                  firstChild: widget1,
                  secondChild: Builder(builder: widget2builder),
                  duration: const Duration(milliseconds: 500),
                  crossFadeState: toggle ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                ),
                const Text("Some text below."),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

If you run this, you will see that Building widget 2 is printed to the console, but widget 1 is the one being displayed.

My questions:

  • Is there any reason why AnimatedCrossFade is building the widget it doesn't use?

  • How can I prevent this problem and use AnimatedCrossFade efficiently?

like image 224
MarcG Avatar asked Aug 08 '18 03:08

MarcG


People also ask

How do you use AnimatedBuilder in flutter?

AnimatedBuilder is useful for more complex widgets that wish to include an animation as part of a larger build function. To use AnimatedBuilder, simply construct the widget and pass it a builder function. For simple cases without additional state, consider using AnimatedWidget.

What is tween animation in flutter?

A linear interpolation between a beginning and ending value. Tween is useful if you want to interpolate across a range. To use a Tween object with an animation, call the Tween object's animate method and pass it the Animation object that you want to modify.

How do you slide transition in flutter?

In Flutter, it's very easy to apply a transition animation to a widget. What you need to do is wrap the widget where the transition animation will be applied on as the child of SlideTransition widget. Then, create an Animation<Offset> to define the transition.


1 Answers

This is the expected behavior.

As stated by the dart team, you should expect the build method the be called at any times. build is designed to be cheap and without side effects.

The fact that a widget is built doesn't mean it's rendered on screen. Opacity with an opacity of 0 actually shortcuts the painting process (and have other optimizations when completely opaque).


If this causes a problem then you should instead use AnimatedSwitcher which plays an animation when its child is replaced.

like image 72
Rémi Rousselet Avatar answered Sep 30 '22 02:09

Rémi Rousselet