Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter does not update subwidget

I have a widget, which contains a subwidget. It get the last and new value in the build method like this:

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

The state will be updatet with

setState

But the widget does not get updated if there are new values.

Did anyone see the issue there?

The class is:

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));
  }
}

Thanks a lot.

like image 813
auryn31 Avatar asked May 22 '18 21:05

auryn31


2 Answers

If you want your animation to restart when the values of the CircleWidget change, you need to use the didUpdateWidget lifecycle. initState is called only once, while didUpdateWidget is called every time your the corresponding widget is recreated - note that the values might be the same if a parent widget rebuilt too.

@override
void didUpdateWidget(CircleWidget oldWidget) {
  if (oldWidget._start != widget._start || 
    oldWidget._end != widget._end) {
    // values changed, restart animation.
    controller
      ..reset()
      ..forward();
  }
  super.didUpdateWidget(oldWidget);
}
like image 165
Jonah Williams Avatar answered Nov 11 '22 12:11

Jonah Williams


I want to post an alternative solution to the given solution above. if you want StatefulWidget to update its underlying data when you call setState or inside a StreamBuilder you should pass a UniqueKey to the StatefulWidget constructor. The behavior of fullter when setState is called is to check if the type did not change in case of StatefulWidget if not nothing will be updated. If you add a UniqueKey to the constuctor, the flutter UI updater will check the key instead. I hope this helps.

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
                      ))
                  ],
                ),
like image 6
Ramdane Oualitsen Avatar answered Nov 11 '22 12:11

Ramdane Oualitsen