Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
173 views
in Technique[技术] by (71.8m points)

flutter - Setstate for statless widget dropdownButton from a stateful parent

I have three widgets first one is LightBulb(stateless) that have some color properties. The second one is widget named as LightColorSelector(stateless) that has a DropdownMenu with string type items Red, Greenand Blue. And, the third class is Classroom(stateful widget) which is the parent of that two classes. My aim is to set the states from that class. I need to set a list of that three colors inside the Classroom, when someone clicks on one of the LightColorSelector items the LightBulb should switches according to clicked color. However, the color inside the LightBulb returns always null. I think it didn't set. Actually, I might know where is the mistake. I think in the LightColorSelector function there is a onChanged property and I didn't set the value into the func(). I marked below where I suspect the mnistake is occur.

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

Sample output,

Output


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can copy paste run full code below
Step 1: Set initial value in _ClassroomState

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

Step 2: Callback function selectLightColor need parameter selectedValue and use if else if, you have logic error here

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

Step 3: LightColorSelector constructor and onChanged need to set initialVal and onChanged need to call 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);
          },

working demo

enter image description here

full code

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...