

SingleChildRenderObjectWidget, RenderBoxを使用してウィジェットを自作しています。  
この自作ウィジェットの親ウィジェットで特定の操作が行われたときにsetState()で描画を更新したいのですが、動作しないことがあります。

以下がサンプルコードです。  
ボタンを押したときに色が黒から赤に変わるのが期待している動作ですが、実際には変わりません。

[code]

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        );
      }
    }
    
    class MyRenderData {
      Color color;
    
      MyRenderData(this.color);
    }
    
    class MyRenderBox extends RenderBox {
      MyRenderData data;
    
      MyRenderBox(this.data);
      @override
      bool get sizedByParent => true;
    
      @override
      void performResize() {
        size = constraints.biggest;
      }
    
      @override
      void paint(PaintingContext context, Offset offset) {
        Canvas c = context.canvas;
        c.drawRect(
            Rect.fromLTRB(offset.dx, offset.dy, offset.dx + 100, offset.dy + 100),
            Paint()..color = data.color);
      }
    }
    
    class MyRenderWidget extends SingleChildRenderObjectWidget {
      MyRenderData data;
    
      MyRenderWidget(this.data);
    
      @override
      RenderObject createRenderObject(BuildContext context) {
        return MyRenderBox(data);
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      // This widget is the home page of your application. It is stateful, meaning
      // that it has a State object (defined below) that contains fields that affect
      // how it looks.
    
      // This class is the configuration for the state. It holds the values (in this
      // case the title) provided by the parent (in this case the App widget) and
      // used by the build method of the State. Fields in a Widget subclass are
      // always marked "final".
    
      final String title;
    
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      MyRenderData data;
    
      @override
      void initState() {
        super.initState();
        this.data = MyRenderData(Colors.black);
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
            child: MyRenderWidget(data),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: () {
              setState(() {
                // こっちは動く
                //data.color = Colors.red;
    
                // こっちは動かない
                this.data = MyRenderData(Colors.red);
              });
            },
          ),
        );
      }
    }
    
    
[/code]

サンプル用プロジェクトは以下のように作成しました。

[code]

    flutter create -t app render_object_test
    
[/code]

これはサンプルなのでかなり小さいですが、  
実際には項目を選択するためのリストと自作ウィジェットが表示されており、  
リストから項目を選択すると項目に対応する内容が自作ウィジェットに表示されるような処理を実装しています。

そちらのコードでも似たような問題が発生しており、  
どうもオブジェクトを変更するのではなく上書きするとこの問題が発生してしまうようなのですが  
なぜそのような動作になるのかが分かりません。  
また、ステートを更新する場合は上書きするのではなく既存のインスタンスを変更するのが正しい実装なのでしょうか？


CC BY-SA 4.0
2021-01-03T08:53:57.390
73043
2023-07-26T08:07:05.813
10677
question
flutter dart
flutterでsetState()を実行しても描画が更新されない


以下のように`MyRenderWidget` に `UniqueKey`を渡せば期待通りになるかと思います。

[code]

    class MyRenderWidget extends SingleChildRenderObjectWidget {
      final MyRenderData data;
    
      const MyRenderWidget(this.data, {Key key}): super(key: key);
    
      @override
      RenderObject createRenderObject(BuildContext context) {
        return MyRenderBox(data);
      }
    }
    
[/code]

[code]

            child: MyRenderWidget(data, key: UniqueKey()),
    
[/code]


CC BY-SA 4.0
2021-04-09T04:46:10.297
75175
2021-04-09T04:46:10.297
40046
73043
answer


dartのバージョンを表示したらもっとわかりやすいと思います。(nullsafeかどうかによって結果が違うので)

可能性は二つあります：

一つはFlutterのWidget変化検出がその変化を検出出来なかった。  
二つはnullsafeでラムダの中にエラーが出てしまった。

[code]

              setState(() {
                // nullsafeの場合はこうして値を代入することができないので
                this.data = MyRenderData(Colors.red);
              });
    
[/code]


CC BY-SA 4.0
2021-12-12T11:29:18.730
84085
2021-12-12T11:29:18.730
41314
73043
answer