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?
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With