Flutter中Radio button如何只选择一组值?

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

我正在使用 Flutter-Dart-SQLite 开发一个测验应用程序。在这里,我使用 RadioListTile 来实现单选按钮功能。我将文本值从一个数组传递给这个

StatefulWidget
。 这是我正在使用的代码,

    import 'package:flutter/material.dart';
    import 'package:get/get_state_manager/get_state_manager.dart';
    import 'package:loginform_validation_demo/QuizApp/controllers/question_controller.dart';
    import 'package:loginform_validation_demo/resource-file/constants.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    import 'package:flutter/src/material/radio_list_tile.dart';

    class OptionRadio extends StatefulWidget {
      final String text;
      final int index;
      final VoidCallback press;

      const OptionRadio({
        Key key,
        this.text,
        this.index,
        this.press,
      }) : super();

      @override
      OptionRadioPage createState() =>
          OptionRadioPage(this.text, this.index, this.press);
    }

    class OptionRadioPage extends State<OptionRadio> {
      final String text;
      int index;
      final VoidCallback press;
      QuestionController controllerCopy =QuestionController();

      int id = 1;
      int selectedButton = null;
      bool _isButtonDisabled;

      OptionRadioPage(this.text, this.index, this.press);

      @override
      void initState() {
        _isButtonDisabled = false;
      }

      int _selected = null;

      @override
      Widget build(BuildContext context) {
        return GetBuilder<QuestionController>(
            init: QuestionController(),
            builder: (qnController) {
              Color getTheRightColor() {
                if (qnController.isAnswered) {
                  if (index == qnController.selectedAns &&
                      qnController.selectedAns == qnController.correctAns) {

                    return kBlackColor;
                  } else if (index == qnController.selectedAns &&
                      qnController.selectedAns != qnController.correctAns) {
                    return kBlackColor;
                  }

                }
                return kBlackColor;
              }

              return InkWell(
                onTap: press,
                child: Container(
                  child: Row(
                    children: <Widget>[
                      Expanded(
                        child: Container(
                            // height: 60.0,
                            child: Theme(
                              data: Theme.of(context).copyWith(
                                  unselectedWidgetColor: Colors.grey,
                                  disabledColor: Colors.blue),
                              child: Column(children:
                              [
                                RadioListTile(
                                  title: Text(
                                    "${index + 1}. $text",
                                    style: TextStyle(
                                        color: getTheRightColor(), fontSize: 16),
                                    softWrap: true,
                                  ),
                                  /*Here the selectedButton which is null initially takes place of value after onChanged. Now, I need to clear the selected button when other button is clicked */
                                  groupValue: selectedButton,
                                  value: index,
                                  activeColor: Colors.green,
                                  onChanged:
                                      (val) async {

                                    debugPrint(
                                        'Radio button is clicked onChanged $val');
                                    setState(() {
                                      debugPrint('Radio button setState $val');
                                      selectedButton = val;
                                      debugPrint('Radio button is clicked onChanged $index');
                                    
                                    });
                                    SharedPreferences prefs = await SharedPreferences.getInstance();
                                    prefs.setInt('intValue', val);
                                  },
                                  toggleable: true,
                                ),
                              ]
                              ),
                            )),
                      ),
                    ],
                  ),
                ),
              );
            });
      }

      @override
      State<StatefulWidget> createState() {
        throw UnimplementedError();
      }
    }

这里的 selectedButton 最初是空的,在

onChanged
之后代替组值的值。现在,我需要在单击另一个按钮时清除所选按钮。

我猜我在组值部分做错了。

我使用OptionRadio的部分,

class QuestionCardWidgetRadio extends StatelessWidget {
  OptionRadio optionRadio = OptionRadio();
  QuestionCardWidgetRadio({
    Key key,
    this.note,
    this.index,
    this.questionLength,
  }) : super(key: key);

  final BlazorQuiz note;
  final int index;
  final int questionLength;
  bool _isAnswered = false;
  bool get isAnswered => this._isAnswered;
  int selectedButton;

  @override
  Widget build(BuildContext context) {
    QuestionController _questionController =
        Get.put(QuestionController());
    debugPrint("Answer Print : ${note.Answer.split(",")}");
    return Container(
        margin: EdgeInsets.symmetric(horizontal: kDefaultPadding, vertical: 35),
        decoration: BoxDecoration(
          color: Colors.white,
        borderRadius: BorderRadius.circular(25),
        ),
        padding: EdgeInsets.all(kDefaultPadding),
    child: SingleChildScrollView(
    scrollDirection: Axis.vertical,
        child: Column(
          children: [
            ...List.generate(
              note.Answer.split(",").length,
              (index) => OptionRadio(
                index: index,
                text: note.Answer.split(",")[index],
                press: (val) => setState(() {
                  selectedButton = int.parse(val.toString());
                  print("$selectedButton");
                }),
                selectedButton: selectedButton,
                // press:
                //       () =>{
                //   _isAnswered = true,
                //   _questionController.checkAns(note, index),
                //     selectedButton,
                // }
              ),

            SingleChildScrollView(
              scrollDirection: Axis.vertical,
              child: TextButton(
                onPressed: () async {
                  debugPrint("Clicked options : ${note.Answer.isNotEmpty} isAnswered: $isAnswered");
                  debugPrint('Check Index : ${index} check quiz model Lenght : ${QuizModel.question.length} check note Id : ${note.Id}');
                  if(index+1 == questionLength){
                    // score screen
                    debugPrint('Navigate to score screen');
                    Text(
                      "Submit",
                      style: Theme.of(context)
                          .textTheme
                          .button
                          .copyWith(color: Colors.white),
                    );
                    _questionController.scoreNavigation(index, context);
                  }
                  else{
                    if (note.Answer.isNotEmpty == !isAnswered) {
                      debugPrint('Clicked RadioBtn ${optionRadio.index}');
                      SharedPreferences prefs = await SharedPreferences.getInstance();
                      //Return int
                      int intValue = prefs.getInt('intValue');
                      debugPrint('Int value from sharedPrefs: $intValue');
                      _questionController.nextQuestion(note,intValue,"","",[]);
                      prefs.remove("intValue");
                    }else{
                      debugPrint('Click proper option for Radio');
                    }
                  }
                },

                child: Container(
                  width: double.infinity,
                  alignment: Alignment.center,
                  padding: EdgeInsets.all(kDefaultPadding * 0.75),
                  margin: EdgeInsets.all(37),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.all(Radius.circular(10)),
                      color: Color(ColorData.button)
                  ),
                  child: Text(
                    "Next Question",
                    style: Theme.of(context)
                        .textTheme
                        .button
                        .copyWith(color: Colors.white),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  setState(Null Function() param0) {}
}

我从数组中获取值,其中选项用逗号分隔。 “答案”:“男,女”

flutter dart radio-button flutter-layout flutter-getx
3个回答
1
投票

这是使用“OptionRadioPage”小部件的示例代码。
(但由于代码泄漏,删除了一些代码)
正如我评论的那样,“groupValue”应该与两个“OptionRadioPage”小部件共享。
所以我存储那个值 'OptionRadioPage' parent widget and
也将该值传递给“OptionRadioPage”小部件。

import 'package:flutter/material.dart';
import 'package:flutter/src/material/radio_list_tile.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Main(),
    );
  }
}

class Main extends StatefulWidget {
  Main({Key key}) : super(key: key);

  @override
  _MainState createState() => _MainState();
}

class _MainState extends State<Main> {
  int selectedButton;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            OptionRadio(
                text: 'Male',
                index: 0,
                selectedButton: selectedButton,
                press: (val) {
                  selectedButton = val;
                  setState(() {});
                }),
            OptionRadio(
                text: 'Female',
                index: 1,
                selectedButton: selectedButton,
                press: (val) {
                  selectedButton = val;
                  setState(() {});
                }),
          ],
        ),
      ),
    );
  }
}

class OptionRadio extends StatefulWidget {
  final String text;
  final int index;
  final int selectedButton;
  final Function press;

  const OptionRadio({
    Key key,
    this.text,
    this.index,
    this.selectedButton,
    this.press,
  }) : super();

  @override
  OptionRadioPage createState() => OptionRadioPage();
}

class OptionRadioPage extends State<OptionRadio> {
  // QuestionController controllerCopy =QuestionController();

  int id = 1;
  bool _isButtonDisabled;

  OptionRadioPage();

  @override
  void initState() {
    _isButtonDisabled = false;
  }

  int _selected = null;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {
        widget.press(widget.index);
      },
      child: Container(
        child: Row(
          children: <Widget>[
            Expanded(
              child: Container(
                  // height: 60.0,
                  child: Theme(
                data: Theme.of(context).copyWith(
                    unselectedWidgetColor: Colors.grey,
                    disabledColor: Colors.blue),
                child: Column(children: [
                  RadioListTile(
                    title: Text(
                      "${widget.index + 1}. ${widget.text}",
                      style: TextStyle(color: Colors.black, fontSize: 16),
                      softWrap: true,
                    ),
                    /*Here the selectedButton which is null initially takes place of value after onChanged. Now, I need to clear the selected button when other button is clicked */
                    groupValue: widget.selectedButton,
                    value: widget.index,
                    activeColor: Colors.green,
                    onChanged: (val) async {
                      debugPrint('Radio button is clicked onChanged $val');
                      // setState(() {
                      //   debugPrint('Radio button setState $val');
                      //   selectedButton = val;
                      //   debugPrint('Radio button is clicked onChanged $widget.index');
                      // });
                      // SharedPreferences prefs = await SharedPreferences.getInstance();
                      // prefs.setInt('intValue', val);
                      widget.press(widget.index);
                    },
                    toggleable: true,
                  ),
                ]),
              )),
            ),
          ],
        ),
      ),
    );
  }
}

1
投票

发生这种情况是因为您正在为每个

Radio
按钮定义单独的 groupValue。与其为每个按钮定义
selectedButton
字段,不如在您调用此
widget
的文件中定义一次,然后将
value
通过它的
constructor
,如下面的代码:

class OptionRadio extends StatefulWidget {
  final String text;
  final int index;
  final ValueChanged<Object> press;
  final int selectButton;

  const OptionRadio({
    Key key,
    this.text,
    this.index,
    this.press, 
    this.selectButton,
  }) : super();

  @override
  OptionRadioPage createState() =>
      OptionRadioPage(this.text, this.index, this.press);
}

并将此

value
press
功能用于您的Radio按钮,如下所示:

                RadioListTile(
                              title: Text(
                                "${index + 1}. $text",
                                style: TextStyle(
                                    color: Colors.green, fontSize: 16),
                                softWrap: true,
                              ),
                              groupValue: widget.selectButton,
                              value: index,
                              activeColor: Colors.green,
                              onChanged: widget.press,
                            )

也通过

ValueChanged(Object)
代替
VoidCallBack

final ValueChanged<Object> press;

并在那里传递适当的功能,例如:

OptionRadio(
                        text: "abc",
                        index: index,
                        press: (val) => setState(() {
                          selectButton = int.parse(val.toString());
                          print("$selectButton");
                        }),
                        selectButton: selectButton,
                      )

0
投票

1) 首先在类中定义Boolean。

class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  bool isAdmin = true; //<-- Here 
}

2) 然后使用三元运算符。

Column(
  children: [
    IconButton(
      onPressed: () {
        setState(() {
          isAdmin = true;
        });
      },
      icon: Icon(
        isAdmin ? Icons.radio_button_on : Icons.radio_button_off, //<-- Here
      ),
    ),
    const Text("Admin") 
  ],
),
Column(
  children: [
    IconButton(
      onPressed: () {
        setState(() {
          isAdmin = false;
        });
      },
      icon: Icon(
        isAdmin ? Icons.radio_button_off : Icons.radio_button_on, //<-- Here
      ),
    ),
    const Text("Customer")
  ],
),
© www.soinside.com 2019 - 2024. All rights reserved.