问题描述
当前,此代码可以调整容器的大小,以在不同的内容之间切换,但这不是动画。我认为我需要提供一个height属性来使动画工作,并且当我确实提供一个可以在其之间切换的高度时,就像这样:
height: selected ? 400 : 100,
容器在两个状态之间平滑地动画。但是,高度不再自适应。所以我尝试使用以下方法提供高度:
GlobalKey _key = GlobalKey();
_size = _key.currentContext.size;
height: _size.height,
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,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,10),child: Row(
children: [
Icon(
Icons.calendar_today,color: Colors.black54,size: 20,Text(
' In three days',style: TextStyle(
color: Colors.black54,child: Row(
children: [
Icon(
Icons.attach_money,Text(
' 30',Row(
children: [
Text('Price : '),Container(
width: 140,margin: EdgeInsets.fromLTRB(0,0),decoration: Boxdecoration(
borderRadius: BorderRadius.circular(20.0),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",keyboardType: TextInputType.multiline,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),textColor: Colors.black,onpressed: () {
/*...*/
},child: Padding(
padding: EdgeInsets.fromLTRB(0,10,child: Text(
"Reply",)
],)
);
}
}
解决方法
我认为AnimatedContainer不适合这种情况。我认为最好使用AnimatedCrossFade。当使用提供的曲线和持续时间更改属性的旧值和新值时,AnimatedContainer将自动在属性的旧值和新值之间设置动画。
使用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,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,10),child: Row(
children: [
Icon(
Icons.calendar_today,color: Colors.black54,size: 20,Text(
' In three days',style: TextStyle(
color: Colors.black54,child: Row(
children: [
Icon(
Icons.attach_money,Text(
' 30',Row(
children: [
Text('Price : '),Container(
width: 140,margin:
EdgeInsets.fromLTRB(0,0),decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(20.0),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,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),textColor: Colors.black,onPressed: () {
/*...*/
},child: Padding(
padding: EdgeInsets.fromLTRB(
0,10,child: Text(
"Reply",)
],secondChild: Container(
// height: !selected ? 100 : 400,));
}
}
,
您可以使用自定义动画来执行此操作,如下所示:
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',);
}
}
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),boxShadow: [
BoxShadow(
blurRadius: 2.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',Text(
'Sarah - 2 days ago - 2.3km',]);
}
}
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,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,child: Row(
children: [
Icon(
Icons.calendar_today,Text(
' In three days',style: TextStyle(
color: Colors.black54,child: Row(
children: [
Icon(
Icons.attach_money,Text(
' 30',Row(
children: [
Text('Price : '),Container(
width: 140,margin: EdgeInsets.fromLTRB(0,decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),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,Row(
children: [
Text('Reply : '),Expanded(
child: TextField(
decoration: new InputDecoration(
hintText: "Enter your reply",keyboardType: TextInputType.multiline,Row(mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
SizedBox(
width: 10,FlatButton(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.blue,borderRadius: BorderRadius.circular(50),onPressed: () {
/*...*/
},child: Padding(
padding: EdgeInsets.fromLTRB(0,child: Text(
"Reply",))
])
]))
]);
}
}