简体   繁体   English

如何使用 Flutter AnimatedContainer 与高度匹配的孩子

[英]How to use Flutter AnimatedContainer with height matching child

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",
                                            ),
                                          ),
                                        ),
                                      ],
                                    )
                                  ],
                                ),
                              ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ],
      )

    );
  }
}

I thing AnimatedContainer is not Appropriate for this situation.我认为 AnimatedContainer 不适合这种情况。 I think its better to use AnimatedCrossFade .我认为最好使用AnimatedCrossFade The AnimatedContainer will automatically animate between the old and new values of properties when they change using the provided curve and duration. AnimatedContainer 将使用提供的曲线和持续时间在属性的旧值和新值之间自动设置动画。

following code is refactored for using AnimatedCrossFade:以下代码被重构以使用 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),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    ));
  }
}

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",
                ),
              ))
        ])
      ]))
    ]);
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM