Reputation: 11
Currently this code works to resize a container to toggle between different content, but it's not animating. I think that I need to provide a height property to make the animation work, and when I do provide a height to toggle between it does match, like this:
height: selected ? 400 : 100,
The container animates smoothly between the two states. However the height is no longer adaptive. So I try to supply a height using:
GlobalKey _key = GlobalKey();
_size = _key.currentContext.size;
height: _size.height,
But it gives me errors and I'm not sure how to fix it.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool selected = false;
// GlobalKey _key = GlobalKey();
// Size _size = _key.currentContext.size;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
// _size = _key.currentContext.size;
});
},
child: Padding(
padding: EdgeInsets.all(5),
child: AnimatedContainer(
// height: _size.height,
// key: _key,
duration: Duration(seconds: 1),
curve: Curves.fastOutSlowIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
if (selected)
Container(
child: Column(
children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
border: Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height:20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue, width: 1, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
"Reply",
),
),
),
],
)
],
),
),
],
),
),
),
),
),
],
),
),
],
)
);
}
}
Upvotes: 1
Views: 2090
Reputation: 121
You can use custom animation to do this, like this:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
bool selected = false;
GlobalKey _key1 = GlobalKey();
GlobalKey _key2 = GlobalKey();
AnimationController _controller;
Animation _animation;
bool foward = false;
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 1));
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_animation = Tween<double>(
begin: _key1.currentContext.size.height,
end: _key2.currentContext.size.height +
_key1.currentContext.size.height)
.chain(CurveTween(curve: Curves.fastOutSlowIn))
.animate(_controller);
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Padding(
padding: EdgeInsets.all(5),
child: GestureDetector(
onTap: () {
if (foward) {
_controller.reverse();
} else {
_controller.forward();
}
foward = !foward;
},
child: (_animation == null)
? _buildWidget(_key1, _key2)
: AnimatedBuilder(
// curve: Curves.fastOutSlowIn,
animation: _controller,
builder: (context, child) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17.0),
child: Container(
height: _animation.value, child: child),
));
},
child: _buildWidget(_key1, _key2)),
),
),
],
)));
}
Widget _buildWidget(Key key1, Key key2) {
return SingleChildScrollView(
physics: const NeverScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Widget1(
key: _key1,
),
Widget2(
key: _key2,
),
],
),
);
}
}
class Widget1 extends StatefulWidget {
Widget1({Key key}) : super(key: key);
@override
_Widget1State createState() => _Widget1State();
}
class _Widget1State extends State<Widget1> {
@override
Widget build(BuildContext context) {
return Column(mainAxisSize: MainAxisSize.min, children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
]);
}
}
class Widget2 extends StatefulWidget {
Widget2({Key key}) : super(key: key);
@override
Widget2State createState() => Widget2State();
}
class Widget2State extends State<Widget2> {
@override
Widget build(BuildContext context) {
return Column(mainAxisSize: MainAxisSize.min, children: [
Container(
child: Column(children: [
Padding(
padding: EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin: EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
border: Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding: const EdgeInsets.all(10.0)),
keyboardType: TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height: 20),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue, width: 1, style: BorderStyle.solid),
borderRadius: BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Text(
"Reply",
),
))
])
]))
]);
}
}
Upvotes: 0
Reputation: 855
I thing AnimatedContainer is not Appropriate for this situation. I think its better to use AnimatedCrossFade. The AnimatedContainer will automatically animate between the old and new values of properties when they change using the provided curve and duration.
following code is refactored for using AnimatedCrossFade:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool selected = false;
// GlobalKey _key = GlobalKey();
// Size _size = _key.currentContext.size;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
children: [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
// _size = _key.currentContext.size;
});
},
child: Padding(
padding: EdgeInsets.all(5),
child: AnimatedCrossFade(
duration: Duration(seconds: 1),
crossFadeState: selected
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
firstChild: Container(
// height: !selected ? 100 : 400,
// key: _key,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
if (selected)
Container(
child: Column(
children: [
Padding(
padding:
EdgeInsets.fromLTRB(0, 20, 0, 20),
child: Text(
'Fridge is a single door. Sitting in kitchen. Need one strong person as I will help move it.',
style: TextStyle(
color: Colors.black54,
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.black54,
size: 20,
),
Text(
' In three days',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 10),
child: Row(
children: [
Icon(
Icons.attach_money,
color: Colors.black54,
),
Text(
' 30',
style: TextStyle(
color: Colors.black54,
),
),
],
),
),
Row(
children: [
Text('Price : '),
Container(
width: 140,
margin:
EdgeInsets.fromLTRB(0, 0, 0, 0),
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(20.0),
color: Colors.white,
border:
Border.all(color: Colors.white),
),
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: "Your price",
contentPadding:
const EdgeInsets.all(
10.0)),
keyboardType:
TextInputType.number,
maxLines: null,
),
),
),
],
),
Row(
children: [
Text('Reply : '),
Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",
contentPadding:
const EdgeInsets.all(10.0)),
keyboardType:
TextInputType.multiline,
maxLines: null,
),
),
],
),
SizedBox(height: 20),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 10,
),
FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue,
width: 1,
style: BorderStyle.solid),
borderRadius:
BorderRadius.circular(50),
),
color: Colors.white,
textColor: Colors.black,
onPressed: () {
/*...*/
},
child: Padding(
padding: EdgeInsets.fromLTRB(
0, 10, 0, 10),
child: Text(
"Reply",
),
),
),
],
)
],
),
),
],
),
),
),
secondChild: Container(
// height: !selected ? 100 : 400,
// key: _key,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 2.5,
spreadRadius: 0.4,
color: Colors.grey,
offset: Offset(0, 0.5),
),
],
),
child: Padding(
padding: EdgeInsets.all(17),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Move fridge up stairs',
style: TextStyle(fontSize: 16),
),
SizedBox(height: 5),
Text(
'Sarah - 2 days ago - 2.3km',
style: TextStyle(color: Colors.black54),
),
],
),
),
),
),
),
),
],
),
),
],
));
}
}
Upvotes: 2