Flutter 不更新子小部件

Posted

技术标签:

【中文标题】Flutter 不更新子小部件【英文标题】:Flutter does not update subwidget 【发布时间】:2018-11-01 17:51:05 【问题描述】:

我有一个小部件,其中包含一个子小部件。它在 build 方法中获取最后一个新值,如下所示:

children: <Widget>[
                    AspectRatio(
                      aspectRatio: 1.0,
                      child: Container(
                        padding: const EdgeInsets.all(16.0),
                        child: CircleWidget(_lastWindSpeed/10, _speed/10),
                      ))
                  ],
                ),

状态将更新为

setState

但如果有新值,小部件不会更新。

有人看到那里的问题吗?

班级是:

import 'package:flutter/material.dart';
import 'circle_painter.dart';

class CircleWidget extends StatefulWidget 
  final double _start;
  final double _finish;
  CircleWidget(this._start, this._finish);

  @override
  State<CircleWidget> createState() => new _CircleState();


class _CircleState extends State<CircleWidget> with SingleTickerProviderStateMixin

  Animation<double> animation;
  double _fraction;

  @override
  void initState() 
    super.initState();
    var controller = AnimationController(duration: new Duration(milliseconds: 10), vsync: this);
    animation = Tween(begin: widget._start, end: widget._finish).animate(controller)
      ..addListener(()
        setState(() 
          _fraction = animation.value;
        );
      );
    controller.forward();
  
  @override
  Widget build(BuildContext context) 
    return new CustomPaint(
        painter: new CirclePainter(_fraction));
  

非常感谢。

【问题讨论】:

【参考方案1】:

如果您希望动画在CircleWidget 的值更改时重新启动,则需要使用didUpdateWidget 生命周期。 initState 只被调用一次,而 didUpdateWidget 在每次重新创建相应的小部件时被调用 - 请注意,如果父小部件也重新构建,值可能相同。

@override
void didUpdateWidget(CircleWidget oldWidget) 
  if (oldWidget._start != widget._start || 
    oldWidget._end != widget._end) 
    // values changed, restart animation.
    controller
      ..reset()
      ..forward();
  
  super.didUpdateWidget(oldWidget);

【讨论】:

“没有得到它的工作”的描述性不足以帮助您。另外一点是 10 毫秒的动画不到一帧,所以它们总是会立即完成 我想我会在这个例子中使用流,我稍后会尝试另一种方式,到目前为止谢谢:-)【参考方案2】:

我想发布上述给定解决方案的替代解决方案。 如果您希望StatefulWidget 在您调用setState 或在StreamBuilder 内更新其基础数据,您应该将UniqueKey 传递给StatefulWidget 构造函数。 当setState 被调用时,fullter 的行为是检查在StatefulWidget 的情况下类型是否没有改变,如果不是什么都不会更新。 如果您将UniqueKey 添加到构造函数,flutter UI 更新程序将改为检查密钥。 我希望这会有所帮助。

import 'package:flutter/material.dart';
import 'circle_painter.dart';

class CircleWidget extends StatefulWidget 
  final double _start;
  final double _finish;
  CircleWidget(this._start, this._finish, Key:key):super(key:key); // <-- check this

  @override
  State<CircleWidget> createState() => new _CircleState();


class _CircleState extends State<CircleWidget> with SingleTickerProviderStateMixin

  Animation<double> animation;
  double _fraction;

  @override
  void initState() 
    super.initState();
    var controller = AnimationController(duration: new Duration(milliseconds: 10), vsync: this);
    animation = Tween(begin: widget._start, end: widget._finish).animate(controller)
      ..addListener(()
        setState(() 
          _fraction = animation.value;
        );
      );
    controller.forward();
  
  @override
  Widget build(BuildContext context) 
    return new CustomPaint(
        painter: new CirclePainter(_fraction));
  




children: <Widget>[
                    AspectRatio(
                      aspectRatio: 1.0,
                      child: Container(
                        padding: const EdgeInsets.all(16.0),
                        child: CircleWidget(_lastWindSpeed/10, _speed/10, key: UniqueKey()), // <---- add UniqueKey as key param here to tell futter to check keys instead of types
                      ))
                  ],
                ),

【讨论】:

以上是关于Flutter 不更新子小部件的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Flutter 的 ListView 中显示特定小部件的子小部件?

Flutter - 无法从父小部件更改子状态

如何从另一个小部件类更新小部件树 - Flutter

Flutter - 与子小部件交互时停止 ListView 滚动

如何在 Flutter 中正确重用 Provider

如何更轻松地实现一个 Flutter 布局?