如何将Flutter AnimatedContainer与高度匹配的子项一起使用

问题描述

当前,此代码可以调整容器的大小,以在不同的内容之间切换,但这不是动画。我认为我需要提供一个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",))
        ])
      ]))
    ]);
  }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...