【问题标题】:Setstate for statless widget dropdownButton from a stateful parent来自有状​​态父级的无状态小部件下拉按钮的 Setstate
【发布时间】:2021-01-12 10:35:16
【问题描述】:

我有三个小部件,第一个是 LightBulb(stateless),它们有一些颜色属性。第二个是名为LightColorSelector(stateless) 的小部件,它有一个DropdownMenu 和字符串类型项目RedGreenBlue。第三类是Classroom(stateful widget),它是这两个类的父类。我的目标是设置该类的状态。 我需要在Classroom 中设置这三种颜色的列表,当有人点击LightColorSelector 项目之一时,LightBulb 应该根据点击的颜色切换。但是,LightBulb 内的颜色始终返回 null。我认为它没有设置。实际上,我可能知道错误在哪里。我认为在LightColorSelector 函数中有一个onChanged 属性,我没有将value 设置为func()。我在下面标记了我怀疑发生错误的地方。

import 'package:flutter/material.dart';

// ignore: must_be_immutable
class LightBulb extends StatelessWidget {
  bool isLit;
  Color color;
  LightBulb(bool isLit, Color color) {
    this.isLit = isLit;
    this.color = color;
    print(color.toString());
  }

  Widget build(BuildContext context) {
    return Container(
      color: isLit ? color : Colors.red,
      padding: EdgeInsets.all(5),
      child: isLit ? Text('ON') : Text('OFF'),
    );
  }
}

class LightButton extends StatelessWidget {
  Function func;
  bool isLightOn;
  LightButton(Function func, bool iSLightOn) {
    this.func = func;
    this.isLightOn = iSLightOn;
  }
  String title() {
    if (isLightOn) return "Turn light off";
    return "Turn light on";
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.symmetric(vertical: 4, horizontal: 12),
      color: Colors.red,
      child: Container(
        color: Colors.blue,
        child: MaterialButton(
          textColor: Colors.white,
          onPressed: () => func(),
          child: Text(
            title(),
            style: TextStyle(color: Colors.white),
          ),
        ),
      ),
    );
  }
}

class Classroom extends StatefulWidget {
  @override
  _ClassroomState createState() => _ClassroomState();
}

class _ClassroomState extends State<Classroom> {
  bool isLightOn = false;
  String title = "Not set yet";
  List<Color> lightColor = [Colors.red, Colors.green, Colors.blue];
  Color color;
  String value;
  selectLightColor() {
    setState(() {
      if (value == 'Red') color = lightColor[0];
      if (value == 'Green') color = lightColor[1];
      if (value == 'Blue')
        color = lightColor[2];
      else
        color = Colors.amber;
    });
  }

  onButtonPressed() {
    setState(() {
      isLightOn = !isLightOn;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        color: Colors.blue,
        padding: EdgeInsets.all(5),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            LightBulb(isLightOn, color),
            LightButton(onButtonPressed, isLightOn),
            LightColorSelector(selectLightColor),
          ],
        ),
      ),
    );
  }
}

class LightColorSelector extends StatelessWidget {
  String initialVal = 'Red';
  Function func;
  LightColorSelector(Function func) {
    this.func = func;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.all(10),
        child: DropdownButton(
          value: initialVal,
          onChanged: (value) => func, // =========== Here the error occurs ==========================
          items: <String>['Red', 'Green', 'Blue']
              .map<DropdownMenuItem<String>>((String value) {
            return DropdownMenuItem<String>(
              value: value,
              child: Text(value),
            );
          }).toList(),
        ));
  }
}

样本输出,

【问题讨论】:

    标签: flutter dart state setstate


    【解决方案1】:

    您可以在下面复制粘贴运行完整代码
    第一步:在_ClassroomState中设置初始值

    class _ClassroomState extends State<Classroom> {
      ..
      Color color = Colors.red;
      String value = 'Red';
    

    第二步:回调函数selectLightColor需要参数selectedValue并使用if else if,这里有逻辑错误

    selectLightColor(String selectedValue) {
        setState(() {
          value = selectedValue;
          if (selectedValue == 'Red') {
            color = lightColor[0];
          } else if (selectedValue == 'Green') {
            color = lightColor[1];
          } else if (selectedValue == 'Blue')
            color = lightColor[2];
          else
            color = Colors.amber;
        });
      }
    

    第三步:LightColorSelectorconstructoronChanged需要设置initialValonChanged需要调用func(value)

    class LightColorSelector extends StatelessWidget {
      String initialVal;
      Function func;
    
      LightColorSelector(Function func, String value) {
        this.func = func;
        this.initialVal = value;
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
            padding: EdgeInsets.all(10),
            child: DropdownButton<String>(
              value: initialVal,
              onChanged: (value) {
                initialVal = value;
    
                func(value);
              },
    

    工作演示

    完整代码

    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,
          ),
          home: Scaffold(body: Classroom()),
        );
      }
    }
    
    // ignore: must_be_immutable
    class LightBulb extends StatelessWidget {
      bool isLit;
      Color color;
      LightBulb(bool isLit, Color color) {
        this.isLit = isLit;
        this.color = color;
        print(color.toString());
      }
    
      Widget build(BuildContext context) {
        return Container(
          color: isLit ? color : Colors.red,
          padding: EdgeInsets.all(5),
          child: isLit ? Text('ON') : Text('OFF'),
        );
      }
    }
    
    class LightButton extends StatelessWidget {
      Function func;
      bool isLightOn;
      LightButton(Function func, bool iSLightOn) {
        this.func = func;
        this.isLightOn = iSLightOn;
      }
      String title() {
        if (isLightOn) return "Turn light off";
        return "Turn light on";
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
          padding: EdgeInsets.symmetric(vertical: 4, horizontal: 12),
          color: Colors.red,
          child: Container(
            color: Colors.blue,
            child: MaterialButton(
              textColor: Colors.white,
              onPressed: () => func(),
              child: Text(
                title(),
                style: TextStyle(color: Colors.white),
              ),
            ),
          ),
        );
      }
    }
    
    class Classroom extends StatefulWidget {
      @override
      _ClassroomState createState() => _ClassroomState();
    }
    
    class _ClassroomState extends State<Classroom> {
      bool isLightOn = false;
      String title = "Not set yet";
      List<Color> lightColor = [Colors.red, Colors.green, Colors.blue];
      Color color = Colors.red;
      String value = 'Red';
    
      selectLightColor(String selectedValue) {
        setState(() {
          value = selectedValue;
          if (selectedValue == 'Red') {
            color = lightColor[0];
          } else if (selectedValue == 'Green') {
            color = lightColor[1];
          } else if (selectedValue == 'Blue')
            color = lightColor[2];
          else
            color = Colors.amber;
        });
      }
    
      onButtonPressed() {
        setState(() {
          isLightOn = !isLightOn;
        });
      }
    
      @override
      Widget build(BuildContext context) {
        return Center(
          child: Container(
            //color: Colors.blue,
            padding: EdgeInsets.all(5),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                LightBulb(isLightOn, color),
                LightButton(onButtonPressed, isLightOn),
                LightColorSelector(selectLightColor, value),
              ],
            ),
          ),
        );
      }
    }
    
    class LightColorSelector extends StatelessWidget {
      String initialVal;
      Function func;
    
      LightColorSelector(Function func, String value) {
        this.func = func;
        this.initialVal = value;
      }
    
      @override
      Widget build(BuildContext context) {
        return Container(
            padding: EdgeInsets.all(10),
            child: DropdownButton<String>(
              value: initialVal,
              onChanged: (value) {
                initialVal = value;
    
                func(value);
              },
              items: <String>['Red', 'Green', 'Blue']
                  .map<DropdownMenuItem<String>>((String value) {
                return DropdownMenuItem<String>(
                  value: value,
                  child: Text(value),
                );
              }).toList(),
            ));
      }
    }
    

    【讨论】:

      【解决方案2】:

      StatelessWidget 没有状态,因此您不能在无状态小部件中设置状态,这就是它称为无状态的原因。如果要设置状态,则需要使用有状态小部件

      【讨论】:

      • 我没有在stateless widget 中设置状态。我正在尝试将参数传递给stateless widget's constructor,并通过该参数从父stateful widget 插入state。请仔细阅读说明。
      • 哦,我明白了,我的错。我不确定您的问题,但使用返回小部件的方法会比使用扩展无状态小部件的类更好,因为在这种情况下您可以轻松访问有状态小部件变量。你也可以在这个方法上做 setState @Demir
      • @Demir 我不确定,但问题可能是您在 LightColorSelector onChanged 方法中使用 func 而不是 func() 。检查它可能对你有用
      猜你喜欢
      • 2020-10-19
      • 2022-11-18
      • 1970-01-01
      • 2021-02-16
      • 2021-12-15
      • 2021-06-11
      • 2020-01-05
      • 1970-01-01
      • 2018-09-01
      相关资源
      最近更新 更多