I'm trying to create a smooth animation using the AnimatedCrossFade widget but I noticed 2 problems:
The desired outcome is that both buttons match the parent's width and that the color and text changes transition smoothly, but here's what happens.
I have multiple TextField widgets that I want to use in the page but some need to be animated in. The problem is that when I put a TextField inside an AnimatedCrossFade widget, the bottom line becomes thinner making the layout look horrible. Here's a comparison of how a TextField looks inside an AnimatedCrossFade (top) and outside of it (bottom).
This code sample should be enough to recreate what I'm trying to explain.
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isExpanded = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
padding: EdgeInsets.symmetric(horizontal: 60, vertical: 60),
children: [
ElevatedButton(
child: Text(_isExpanded ? "Collapse" : "Expand"),
onPressed: () {
setState(() {
_isExpanded = !_isExpanded;
});
},
),
AnimatedCrossFade(
crossFadeState: _isExpanded
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(seconds: 1),
firstChild: TextField(
decoration: InputDecoration(
hintText: "Text",
),
),
secondChild: SizedBox.shrink(),
),
TextField(
decoration: InputDecoration(
hintText: "Text",
),
),
AnimatedCrossFade(
crossFadeState: !_isExpanded
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: Duration(seconds: 1),
firstChild: ElevatedButton(
child: Text("Button 1"),
onPressed: () {},
),
secondChild: ElevatedButton(
child: Text("Button 2"),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
onPressed: () {},
),
),
],
),
);
}
}
Hope this is what you want?
I think to handle this case, you need to use layoutBuilder
of AnimatedCrossFade
if you click on layoutBuilder
you can find details.
Updated
wrap with padding to solve TextFiledFormat
, for more you can use decoration
.
To use max width i used like this
AnimatedCrossFade(
crossFadeState: _isExpanded
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: const Duration(seconds: 1),
firstChild: Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: TextField(
key: ValueKey("text1"),
decoration: InputDecoration(
hintText: "Text1",
),
),
),
secondChild: SizedBox.shrink(),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4),
child: TextField(
key: ValueKey("text2"),
decoration: InputDecoration(
hintText: "Text",
),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: AnimatedCrossFade(
crossFadeState: !_isExpanded
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
duration: Duration(seconds: 1),
alignment: Alignment.center,
layoutBuilder:
(topChild, topChildKey, bottomChild, bottomChildKey) {
return topChild;
},
secondChild: ElevatedButton(
child: Text("Button 2"),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
onPressed: () {},
),
firstChild: ElevatedButton(
child: Text("Button 1"),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
),
onPressed: () {},
),
),
),
To get default size of button wrapped with Center inside layoutBuilder
layoutBuilder:
(topChild, topChildKey, bottomChild, bottomChildKey) {
return topChild;
},