Flutter - 如何提取内部带有 onPressed setState 的 Widget?

问题描述 投票:0回答:4

我想提取一个带有

onPressed
setState
的小部件,但我收到消息“无法提取对封闭类方法的引用。” 有办法做到吗?

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

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
4个回答
6
投票

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

0
投票

Setstate 与您想要刷新其状态的小部件相关。如果将其提取到其他位置,则 setState 指的是新小部件的状态。

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

除非,您使用

exact type
查找所需小部件的状态,然后在那里触发该状态,但这太过分了,比您当前拥有的代码要困难得多,需要更多代码。


0
投票

您可以在提取小部件上使用

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

0
投票

在颤动中: 提取小部件

“无法提取对封闭类方法的引用”,错误

当我们尝试提取的小部件使用 setState 时,就会发生这种情况

(特定于有状态小部件)

这意味着 = 无法访问 setState 方法

如何解决这个问题?

  1. 提取为函数
  2. 提取为小部件 a-Extract 作为无状态小部件 b-提取为有状态小部件:

b-1:使用回调提取: 该小部件是有状态的,但它通过回调将状态更改传达给其父级,这维护了状态的单一事实来源。

b-2:无需回调即可提取 在这种情况下,每个实例都有自己的内部状态(隔离)。 这导致父小部件难以控制或访问状态。

大多数情况下,我们要么提取为函数、无状态小部件,要么提取为带回调的有状态小部件。

何时提取为有状态小部件而不需要回调?

  • 如果小部件是独立的并且不需要影响应用程序的其他部分。
  • 如果它是具有独立动画或临时 UI 更改的小部件,则不需要与其他小部件同步。
© www.soinside.com 2019 - 2024. All rights reserved.