【问题标题】:Flutter - How to Extract Widget with onPressed setState inside?Flutter - 如何在内部使用 onPressed setState 提取小部件?
【发布时间】:2021-11-11 17:00:40
【问题描述】:

我想提取一个内部带有onPressedsetState 的小部件,但我收到消息“无法提取对封闭类方法的引用。” 有没有办法做到这一点?

我想将我的代码分成不同的小部件,以便保持清晰。下面是一个简化的代码示例:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

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

class Calculator extends StatefulWidget {
  @override
  _CalculatorState createState() => _CalculatorState();
}

class _CalculatorState extends State<Calculator> {
  var myValue = 0;

  void calculate() {
    myValue = 12;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            child: TextButton(
              onPressed: () {
                setState(() {
                  calculate();
                });
              },
              child: Text(
                'Button 001',
              ),
            ),
          ),
          TextOutput(myValue: myValue),
        ],
      ),
    );
  }
}

class TextOutput extends StatelessWidget {
  const TextOutput({
    Key key,
    @required this.myValue,
  }) : super(key: key);

  final int myValue;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(
        myValue.toString(),
      ),
    );
  }
}

我要提取到单独的小部件中的部分:

  Container(
    child: TextButton(
      onPressed: () {
        setState(() {
          calculate();
        });
      },
      child: Text(
        'Button 001',
      ),
    ),
  ),

【问题讨论】:

    标签: flutter android-studio widget


    【解决方案1】:

    Flutter 为子控件和父控件之间的回调样式事件提供了 VoidCallback 和 Function(x)(其中 x 可以是不同的类型)。

    你可以通过构造函数传递Function onPressed; 这是您提取的容器小部件:

    class ExtractedContainer extends StatelessWidget {
      final Function onPressed;
      const ExtractedContainer({
        Key key, @required this.onPressed,
      }) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Container(
          child: TextButton(
            onPressed: () {
              onPressed();
            },
            child: Text(
              'Button 001',
            ),
          ),
        );
      }
    }
    

    以及如何使用它:

      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ExtractedContainer(onPressed: calculate,),
              TextOutput(myValue: myValue),
            ],
          ),
        );
      }
    

    您的完整代码示例

    import 'package:flutter/material.dart';
    
    class MyApp2 extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Calculator(),
        );
      }
    }
    
    class Calculator extends StatefulWidget {
      @override
      _CalculatorState createState() => _CalculatorState();
    }
    
    class _CalculatorState extends State<Calculator> {
      var myValue = 0;
    
      void calculate() {
        myValue = 12;
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ExtractedContainer(onPressed: calculate,),
              TextOutput(myValue: myValue),
            ],
          ),
        );
      }
    }
    
    class ExtractedContainer extends StatelessWidget {
      final Function onPressed;
      const ExtractedContainer({
        Key key, @required this.onPressed,
      }) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Container(
          child: TextButton(
            onPressed: () {
              onPressed();
            },
            child: Text(
              'Button 001',
            ),
          ),
        );
      }
    }
    
    class TextOutput extends StatelessWidget {
      const TextOutput({
        Key key,
        @required this.myValue,
      }) : super(key: key);
    
      final int myValue;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          child: Text(
            myValue.toString(),
          ),
        );
      }
    }
    

    【讨论】:

      【解决方案2】:

      Setstate 与要刷新其状态的小部件有关。如果你把它提取到另一个地方,那么 setState 指的是新小部件的状态。

      在您的情况下,setState 只会更改封装您尝试提取的小部件及其子级的容器的状态,它不会向上迁移。

      除非您使用exact type 查找您想要的小部件的状态,然后在那里触发该状态,但这有点矫枉过正,难度更大,需要的代码比您目前拥有的更多。

      【讨论】:

        【解决方案3】:

        您可以在提取小部件上使用VoidCallback 来获取onPressed 事件

        class MyContainer extends StatelessWidget {
          final VoidCallback onTap;
          const MyContainer({
            Key? key,
            required this.onTap,
          }) : super(key: key);
        
          @override
          Widget build(BuildContext context) {
            return Container(
              child: TextButton(
                onPressed: onTap,
                child: Text(
                  'Button 001',
                ),
              ),
            );
          }
        }
        

        并使用喜欢

                  MyContainer(
                    onTap: () {
                      print("tapped");
        
                      setState(() {
                        calculate();
                      });
                    },
                  ),
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-05
          • 2018-07-28
          • 1970-01-01
          • 2018-08-10
          • 2021-05-01
          • 2020-08-18
          • 1970-01-01
          • 2021-01-12
          相关资源
          最近更新 更多