如何在 Flutter 中只选择一组单选按钮的值?
Posted
技术标签:
【中文标题】如何在 Flutter 中只选择一组单选按钮的值?【英文标题】:How to select only one group value of Radio button in Flutter? 【发布时间】:2021-12-29 10:52:54 【问题描述】:我正在使用 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 最初为 null 代替 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)
我从一个以逗号分隔选项的数组中获取值。 “答案”:“男,女”
【问题讨论】:
您需要将 'selectedButton' 值保存在 'OptionRadio' 小部件之外,并与 'Male' 的 'OptionRadio' 小部件和 'Female' 的 'OptionRadio' 小部件共享该值。 @KuKu 我测试了上面的方法并且能够接收到在日志中被点击的正确值,但是图标没有改变颜色。对于两者,Icon 保持未选中状态。我试图用 setState() 中的指定值制作一个小部件。选定按钮 = val;因为它是最终字段,所以无法赋值。接下来我该怎么办? 【参考方案1】:这是使用“OptionRadioPage”小部件的示例代码。 (但由于代码泄漏,部分代码被删除) 正如我评论的那样,“groupValue”应该与两个“OptionRadioPage”小部件共享。 所以我存储该值“OptionRadioPage”父小部件和 还将该值传递给“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,
),
]),
)),
),
],
),
),
);
【讨论】:
【参考方案2】:发生这种情况是因为您为每个 Radio 按钮定义了单独的 groupValue
。而不是为每个按钮定义selectedButton
字段,而是在您调用此widget
的文件中定义一次,然后通过constructor
传递value
,如下代码所示:
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,
)
【讨论】:
感谢您的回答。我尝试了上面的代码,在日志中我能够获得被点击的正确值,但图标不会变成任何颜色。两者的图标均未选中。我试图将 setState() 中的选定值分配为 widget.selectButton = val;但由于它的最终字段无法赋值。接下来我该怎么办? 请检查更新的答案,并将 selectButton 类型更改为 int。如果有任何问题,请告诉我。 当我给出静态文本值时没有问题出现,但是在这里我从数组中获取值并且当我在我的 OptionRadio 类中实现此代码时,Scaffold 部分发生错误。我添加了有关我使用此 OptionRadio 的位置的更多详细信息。请帮我解决这个问题,我被这个问题困扰了好几天 当您传递静态值时,我上面的答案工作正常吗? 确保您传递相同数据类型的相同值。以上是关于如何在 Flutter 中只选择一组单选按钮的值?的主要内容,如果未能解决你的问题,请参考以下文章