Flutter 动画容器

6
我在一个屏幕中有一个RaisedButton小部件和一个AnimatedContainer小部件,当按下RaisedButton时,AnimatedContainer的宽度会在给定的时间内减少。 AnimatedContainer的文档说明只需要声明小部件的宽度为变量,然后在更改该值后进行setState(() {})操作,它将在持续时间内自动更改为该值。 我尝试了实现此操作,并且在按下RaisedButton后,变量的值肯定会更改(基于在按下按钮后打印其值),但小部件的宽度并未随之更改。我是否遗漏了明显的东西?
我的小部件在PageView的容器中,我的RaisedButtonAnimatedContainer代码如下:
RaisedButton (
  onPressed: () {
    setState(() {
      loginWidth = 70.0;
    });
  },
),
AnimatedContainer (
 duration: new Duration (seconds: 2),
 width: loginWidth,
 height: 40,
 color: Colors.red,
)

这是我的小部件树:

pages.add(
      Container(
        color: chSecondary,
        child: Stack(
          children: <Widget>[
            Container (
              child: Align (
                child: Image(image: AssetImage("graphics/signin.png")),
                alignment: Alignment.bottomCenter,
              ),
            ),
            Form(
              key: _formKey,
              child: new Container(
                padding: EdgeInsetsDirectional.only(top: 100, start: 15, end: 15, bottom: 15),
                child: new Column(
                  children: <Widget>[
                    Container (
                      child: Image(image: AssetImage("graphics/login.png"), height: 200, width: 200,),
                      margin: EdgeInsetsDirectional.only(bottom: 20),
                    ),
                    Container (
                      padding: EdgeInsets.all(25.0),
                      decoration: new BoxDecoration(
                        borderRadius: BorderRadius.circular(10.0),
                        color: Colors.white,
                      ),
                      child: Column (
                        children: <Widget>[
                          Align(
                            child: new Text("Email:", style: TextStyle(fontSize: tonSubTitle, color: Colors.black)),
                            alignment: Alignment.centerLeft,
                          ),
                          new Container(
                            child: new TextFormField(
                              keyboardType: TextInputType.emailAddress,
                              controller: _email,
                              style: TextStyle(fontSize: tonText, color: Colors.black),
                              decoration: InputDecoration(
                                border: OutlineInputBorder(borderRadius: new BorderRadius.circular(tonRadius)),
                                contentPadding: EdgeInsetsDirectional.only(top: 15, start: 7.5),
                                focusedBorder: OutlineInputBorder(borderSide: new BorderSide(color: Colors.grey)),
                                hintText: "Email Address",
                                hintStyle: TextStyle(color: Colors.black),
                              ),
                              validator: (value) {
                                if (value.isEmpty) {
                                  return "Please enter an email";
                                }
                                if (!value.contains("@tonbridge-school.org")) {
                                  return "Please enter a valid email address";
                                }
                              },

                            ),
                            padding: const EdgeInsets.only(top: 10, bottom: 10)
                          ),
                          Align (
                            child: new Text("Password:", style: TextStyle(fontSize: tonSubTitle, color: Colors.black)),
                            alignment: Alignment.centerLeft,
                          ),
                          new Container(
                            child: new TextFormField(
                              obscureText: true,
                              controller: _password,
                              style: TextStyle(color: Colors.black, fontSize: tonText),
                              decoration: InputDecoration(
                                contentPadding: EdgeInsetsDirectional.only(top: 15, start: 7.5),
                                border: OutlineInputBorder(borderRadius: new BorderRadius.circular(tonRadius)),
                                focusedBorder: OutlineInputBorder(borderSide: new BorderSide(color: Colors.grey)),
                                hintText: "Password",
                                hintStyle: TextStyle(color: Colors.black),
                              ),
                              validator: (value) {
                                if (value.isEmpty) {
                                  return "Please enter a password";
                                }
                              },
                            ),
                            padding: const EdgeInsets.only(top: 10, bottom: 10)
                          ),
                          RaisedButton (
                            onPressed: () {
                              setState(() {
                                loginWidth = 70.0;
                              });
                            },
                          ),
                          AnimatedContainer (
                            duration: new Duration (seconds: 2),
                            width: loginWidth,
                            height: 40,
                            color: Colors.red,
                          )
                        ],
                      ),
                    )
                  ],
                ),
              )
            ),
          ],
        ),
      ),
    );

你能分享更多的小部件树吗?问题不在你的代码片段中。 - Rémi Rousselet
@RémiRousselet 我已经编辑了问题并添加了我的小部件树。 - RhysD
我曾经遇到过类似的问题,那是因为我用于动画的变量不是全局的。我认为如果变量的作用域在构建方法内部,动画就无法正常工作。 - Varundroid
@Varundroid - 这样做是可行的,但大多数情况下,最好将状态变量作用域限定在状态小部件中。如果它们在更大的范围内声明,则可能会出现奇怪的副作用,如果其他正在运行的代码改变了该值。变量应尽可能接近构建器方法的作用域,但不应在其中。请参见下面的答案以获取示例代码片段。 - Curt Eckhart
3个回答

4
您发布的代码片段已经正确无误。请确保以下几点:
  • loginWidth已被初始化
  • 新的loginWidth值实际上与默认值不同
我复制了它并创建了一个最简示例,这样您就可以检查您其余的代码。该示例还包括一个周围的PageView

Demo

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: MyBody(),
      ),
    );
  }
}

class MyBody extends StatefulWidget {
  @override
  _MyBodyState createState() => _MyBodyState();
}

class _MyBodyState extends State<MyBody> {
  double loginWidth = 40.0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: PageView(
        children: <Widget>[
          Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              RaisedButton (
                child: Text('Animate!'),
                onPressed: () {
                  setState(() {
                    loginWidth = 250.0;
                  });
                },
              ),
              AnimatedContainer (
                duration: Duration (seconds: 1),
                width: loginWidth,
                height: 40,
                color: Colors.red,
              ),
            ],
          )
        ],
      ),
    );
  }
}

我使用了你的代码示例来确保我没有漏掉任何明显的问题,但它仍然无法正常工作。你使用的Flutter版本是什么?我的Android Studio / Xcode版本是否会对此产生影响? - RhysD
我正在使用 Flutter (Channel master, v1.3.11-pre.39, on Mac OS X 10.14.3 18D109, locale de-DE)。你的Flutter版本可能会在这里有所改变,但Android Studio和Xcode不应该修改任何内容。 - NiklasPor
运行beta版本会导致动画无法正常工作的可能性有多大?我使用它是因为在主通道的最新版本中,安卓键盘无法正常工作。 - RhysD
不知道成功的概率有多大,但你可以将版本更改为主要版本,查看是否有效,然后再将其更改回测试版。 - NiklasPor

0

你初始化了loginWidth吗?

var loginWidth =0.0;
Curve _curve = Curves.fastOutSlowIn;
_doanimation(){

setState(() {
    loginWidth ==0.0? loginWidth =100: loginWidth =0.0;
   });
}

根据您的情况更改函数

    Column(
            children: <Widget>[
              Text("welcome"),
              RaisedButton(
                onPressed: (){
                  _doanimation();
                },
              ),
              AnimatedContainer(
                curve: _curve,
                duration: Duration(seconds: 1),
                width: loginWidth,
                height:100

              )
            ],
          ),

我已经尝试过这个方法,但动画仍然无法正常播放。这可能与它位于PageView中有关。 - RhysD
PageView不应该是一个问题。在我上面的例子中,我也使用了PageView - NiklasPor

0

你在哪里声明了loginWidth?它需要在构建函数的作用域之外,否则它的值会在每次构建时重新初始化。

你能更新一下你的示例来展示你在哪里声明了吗?

正确的:

class _WidgetState extends State<Widget> {
  double loginWidth = 0;

  @override
  Widget build(BuildContext context) {
    // return the new widget tree
  }
}

不正确:

class _WidgetState extends State<Widget> {

  @override
  Widget build(BuildContext context) {
    double loginWidth = 0;

    //return the new widget tree
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接