1

好的,我正在尝试更具体。我的目标是将部分代码细分为单独的小部件,以便主树尽可能保持干净。

在以下示例中,我在 StatefulWidget 中有一个主树。我已经成功地将带有按钮的容器转换为带有Extract to Widget的自己的小部件。按钮的setState通过构造函数起作用。

现在我想对第二个装有滑块的容器做同样的事情。但我不知道如何使用构造函数处理 Slider onChanged setState,因为 setState 在提取的 Widget 中不起作用。

这是代码示例,其中工作按钮作为提取的小部件,滑块仍在主树内。

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

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

class MyStfl extends StatefulWidget {
  @override
  _MyStflState createState() => _MyStflState();
}

class _MyStflState extends State<MyStfl> {
  double sliderPos = 0.0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        decoration: BoxDecoration(
          color: Color(0x80061A28),
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Expanded(
              child: MyCardA(
                aktion: () {
                  setState(() {
                    print('Button Pressed');
                  });
                },
              ),
            ),
            Expanded(
              child: Container(
                child: Slider(
                  divisions: 48,
                  value: sliderPos,
                  min: 0.0,
                  max: 24.0,
                  onChanged: (double newValue) {
                    setState(
                      () {
                        sliderPos = double.parse(newValue.toStringAsFixed(1));
                        print(sliderPos);
                      },
                    );
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class MyCardA extends StatelessWidget {
  MyCardA({this.aktion});
  final Function aktion;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(20.0),
      padding: EdgeInsets.all(20.0),
      color: Color(0x80125889),
      child: GestureDetector(
        onTap: aktion,
        child: Text(
          'MY BUTTON',
          style: TextStyle(
            color: Color(0xFF3D3939),
            fontSize: 22.0,
          ),
        ),
      ),
    );
  }
}
4

1 回答 1

1

首先,您要在CardA组件中更改一件事。aktion与其将参数键入为Function(这是非常通用的),不如给它一个类型void Function(),说:它是一个不返回任何内容(void)的函数。这是期望的onTap参数。GestureDetector传递任何其他类型的函数不是您想要做的事情,因为它会破坏您的应用程序。输入参数时尽可能具体。您可以将此void Function()类型缩短为VoidCallback. 这是同一件事。

我也做了参数required。这不是必需的,但这是你想要的(我认为)。如果您希望能够发出此参数,请去掉required关键字并键入您的aktionas void Function()??表示您可以通过void Function()null

class MyCardA extends StatelessWidget {
  MyCardA({required this.aktion});
  final void Function() aktion;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(20.0),
      padding: EdgeInsets.all(20.0),
      color: Color(0x80125889),
      child: GestureDetector(
        onTap: aktion,
        child: Text(
          'MY BUTTON',
          style: TextStyle(
            color: Color(0xFF3D3939),
            fontSize: 22.0,
          ),
        ),
      ),
    );
  }
}

对于“MyCardB”,您需要设置一个带有参数的回调函数。它有点复杂。

Slider组件有一个参数onChanged,当滑块位置改变时触发。这为您提供了一个double(新职位)并允许您使用它来做事。这键入为void Function(double)。我们有一个以 adouble作为参数的函数,它什么也不返回 ( void)。

您可以在下面的自定义组件中看到它的外观。

class MyCardB extends StatelessWidget {
  const MyCardB({
    required this.sliderPos,
    required this.onChanged,
  });

  final double sliderPos;
  final void Function(double) onChanged;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Slider(
        divisions: 48,
        value: sliderPos,
        min: 0.0,
        max: 24.0,
        onChanged: onChanged,
      ),
    );
  }
}

你在你的主要组件中使用这个新组件,如下所示。

Expanded(
  child: MyCardB(
    sliderPos: sliderPos,
    onChanged: (double newValue) {
      setState(
        () {
          sliderPos = double.parse(newValue.toStringAsFixed(1));
        },
      );
    },
  ),
),

长话短说,你想利用callback functions. 如果您对它们不熟悉,我敦促您阅读它们,它们非常重要。正如您正确地注意到的那样,您无法在子小部件内执行逻辑;您想将其保留在其父级中。您可以通过创建这些回调函数来管理它。

您在父级中创建回调函数。您将函数传递给您的子小部件。一旦触发,就会在父级内部执行一个函数。孩子只知道它必须触发该功能,但所有逻辑都对其隐藏。

于 2021-09-20T13:09:49.187 回答