我正在使用 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) {}
}
我从数组中获取值,其中选项用逗号分隔。 “答案”:“男,女”
这是使用“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,
),
]),
)),
),
],
),
),
);
}
}
发生这种情况是因为您正在为每个
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,
)
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")
],
),