94245


現在Flutterの学習を進めております。学習の一環で、DoropdownButtonのアイテムに、IconやTextを含む自作したWidgetを使いたいと考え以下のコードを作成しました。実行したところ画面に描画はされるのですが、一度タップすると以下のエラーが発生してしまいアイテムの選択やその後の操作ができません。  
（お恥ずかしながら、エラーメッセージを読んでも何を修正すればよいのか分からず。。。）

【エラーメッセージ】

[code]

    The following assertion was thrown building Container(AlignmentDirectional.centerStart, constraints: BoxConstraints(0.0<=w<=Infinity, 48.0<=h<=Infinity)):
    'package:flutter/src/widgets/framework.dart': Failed assertion: line 5067 pos 12: 'state._element == null': is not true.
    
[/code]

DropMenuItemのchildに指定できるWidgetの複雑さに制限があったり、そもそもDropdownMenuItemにはTextしか指定できないなど制約があったりするのでしょうか？  
DropdownButtonのアイテムに自作のWidgetを使用するにはどのように修正すればよいでしょうか。

【コード】

[code]

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(
          MyApp()
      );
    }
    
    class MyApp extends StatelessWidget {
    
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'DropdownButton Test',
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
    
      State<MyHomePage> createState() {
        return _MyHomePageState();
      }
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
      List<DropdownMenuItem> _itemArray = [];
    
      _MyHomePageState() {
        for(int i = 0; i < 2; ++i) {
          _itemArray.add(
              DropdownMenuItem(
                value: i,
                child: MyListItem(i),
              )
          );
        }
      }
    
      void onChangedDropdownList(dynamic value) {
        print('onChangedDropdownList value = ${value}');
      }
    
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Container(
                child: DropdownButton(
                  value: 0,
                  items: _itemArray,
                  onChanged: onChangedDropdownList,
                )
            ),
          ),
        );
      }
    }
    
    class MyListItem extends StatefulWidget {
    
      late _MyListItemState _myListItemState;
      int _testIndex;
    
      MyListItem(
          this._testIndex,
      ) {
        _myListItemState = _MyListItemState(this);
      }
    
      State<StatefulWidget> createState() {
        return _myListItemState;
      }
    }
    
    class _MyListItemState extends State<MyListItem> {
    
      MyListItem _myListItem;
    
      _MyListItemState(
          this._myListItem,
      ) {
    
      }
    
      void _setStateSample() {
        setState(() {
    
        });
      }
    
      Widget build(BuildContext context) {
        return Container(
            color: Colors.yellow,
            child: Row(
              children: [
                Icon(Icons.person),
                Text('Test Index = ${_myListItem._testIndex}, '),
                Text('AAABBBCCC'),
              ],
            )
        );
      }
    }
    
    
[/code]


CC BY-SA 4.0
2023-03-17T14:55:48.737
94226
2023-03-19T12:18:33.903
57343
question
flutter
Flutterで、DropdownButtonのアイテムに自作のWidgetを使うには


>
> DropMenuItemのchildに指定できるWidgetの複雑さに制限があったり、そもそもDropdownMenuItemにはTextしか指定できないなど制約があったりするのでしょうか？

複雑だったり、大きかったりなどの理由で配置でエラーがでるかもしれないけど、今回のエラー原因は異なるようです。

直接的な原因は、MyListItemのcreateStateで作るべきStateを、コンストラクタで作った物を返してるところかな。  
createStateでは毎回新規にStateを作らないと駄目なはずが、そうではないのでフレームワーク内で必要とするオブジェクトがなくなってエラーと認識されていたようです。

StatefulWidgetについてきちんと習得しなおしたほうが良いです。

一応、動く感じに修正したのが以下のコードです。  
問題だと思い修正したところには、コメント入れておきますので参考にしてください。

[code]

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'DropdownButton Test',
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      State<MyHomePage> createState() {
        return _MyHomePageState();
      }
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      List<DropdownMenuItem> _itemArray = [];
    
      @override
      void initState() {
        // コンストラクタの{}内で変数の初期化をするのは望ましくない
        // 初回だけ実行するコードはinitState内に置く
        for (int i = 0; i < 2; ++i) {
          _itemArray.add(DropdownMenuItem<int>(
            value: i,
            child: MyListItem(i),
          ));
        }
      }
    
      void onChangedDropdownList(dynamic value) {
        print('onChangedDropdownList value = ${value}');
      }
    
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: Container(
                child: DropdownButton(
              value: 0,
              items: _itemArray,
              onChanged: onChangedDropdownList,
            )),
          ),
        );
      }
    }
    
    class MyListItem extends StatefulWidget {
      final int _testIndex;
    
      const MyListItem(
        this._testIndex,
      );
    
      // 以下の様に記述するのがマストになる
      @override
      State<StatefulWidget> createState() {
        return _MyListItemState();
      }
    }
    
    class _MyListItemState extends State<MyListItem> {
      Widget build(BuildContext context) {
        return Container(
            color: Colors.yellow,
            child: Row(
              children: [
                Icon(Icons.person),
                // StatefulWidget内の変数はwidget.変数名でアクセスできる
                Text('Test Index = ${widget._testIndex}, '),
                Text('AAABBBCCC'),
              ],
            ));
      }
    }
    
[/code]


CC BY-SA 4.0
2023-03-19T12:18:33.903
94245
2023-03-19T12:18:33.903
54446
94226
answer