在颤动中洗牌单选按钮
shuffling radio button in flutter
假设我想制作一个可以随机播放单选按钮选项的测验页面。
我已经尝试在初始状态下随机播放 List()(包含单选按钮),但它不起作用。单选按钮工作得很好,但它不会随机播放。这是我的清单
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
];
}
然后我使用我的第二个 tot 制作列表,但我将在 initState 中使用 listRadioOption() 对其进行初始化,如下所示:
late List<Widget> list2; //list for checking my second tot..
这是我的 initState :
@override
void initState() {
super.initState();
print("---- INIT STATE ----");
listRadioOption().shuffle(); //this doesn't shuffle the option, but radio option works perfectly
list2 = listRadioOption(); //this work if i use this as children,
list2.shuffle(); //but it won't changing radio option value when user click in it (i dont know why)
}
list2 可以很好地随机播放,但最终导致用户无法按单选按钮中的任何按钮。我的 listRadioOption() 工作正常,但不能随机播放。
我再次尝试使用这样的级联运算符:
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
]..shuffle();
}
它可以工作,但是当用户按下任何单选按钮时它会一直随机播放。
我对级联运算符略知一二,但是如果我像上面的代码那样在 return 语句中使用它意味着什么?
我想要的实际上只是随机播放单选按钮(1 次),单选按钮会根据用户的点击而改变
谁能帮帮我?
这是我的完整代码:
import 'package:flutter/material.dart';
enum ListJawaban{
answer1,
answer2,
answer3,
answer4,
answer5
}
class QuizTemplate extends StatefulWidget {
const QuizTemplate({
Key? key,
required this.question,
required this.option1,
required this.option2,
required this.option3,
required this.option4,
required this.option5,
required this.qNumber
}) : super(key: key);
final String question;
final String option1;
final String option2;
final String option3;
final String option4;
final String option5;
final int qNumber;
@override
State<QuizTemplate> createState() => _QuizTemplateState();
}
class _QuizTemplateState extends State<QuizTemplate> {
ListJawaban? _value = null;
Widget radioListTile({required String text, required ListJawaban jawaban}){
return RadioListTile<ListJawaban>(
title: Text("$text"),
value: jawaban,
groupValue: _value,
onChanged: (ListJawaban? newValue){
setState(() {
print("jawaban : $newValue");
_value = newValue;
});
},
);
}
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
];
}
late List<Widget> list2; //list for checking my second tot..
@override
void initState() {
super.initState();
print("---- INIT STATE ----");
listRadioOption().shuffle(); //this doesn't shuffle the option, but radio option works perfectly
list2 = listRadioOption(); //this work if i use this as children,
list2.shuffle(); //but it won't changing radio option value when user click in it (i dont know why)
}
@override
Widget build(BuildContext context) {
print("---- BUILD ----");
return Container(
child: Column(
children: [
Text("${widget.qNumber}. ${widget.question}",style: TextStyle(
fontSize: 20,
),),
Builder(
//i actually didn't need this builder, but i used it just for checking variables
builder: (context){
print("---- BUILDER ----");
listRadioOption().shuffle();
return Column(
children: listRadioOption(),
//children: list2,
);
},
)
],
),
);
}
}
更新
这是我的随机播放工作,但我无法更改值:
import 'package:flutter/material.dart';
enum ListJawaban{
answer1,
answer2,
answer3,
answer4,
answer5
}
class QuizTemplate extends StatefulWidget {
const QuizTemplate({
Key? key,
required this.question,
required this.option1,
required this.option2,
required this.option3,
required this.option4,
required this.option5,
required this.qNumber
}) : super(key: key);
final String question;
final String option1;
final String option2;
final String option3;
final String option4;
final String option5;
final int qNumber;
@override
State<QuizTemplate> createState() => _QuizTemplateState();
}
class _QuizTemplateState extends State<QuizTemplate> {
ListJawaban? _value = null;
Widget radioListTile({required String text, required ListJawaban jawaban}){
return RadioListTile<ListJawaban>(
title: Text("$text"),
value: jawaban,
groupValue: _value,
onChanged: (ListJawaban? newValue){
setState(() {
print("jawaban : $newValue");
_value = newValue;
});
},
);
}
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
];
}
late List<Widget> list2; //list for checking my second tot..
List<Widget> option(){
return list2;
}
@override
void initState() {
super.initState();
print("---- INIT STATE ----");
// listRadioOption().shuffle(); //this doesn't shuffle the option, but radio option works perfectly
list2 = listRadioOption(); //this work if i use this as children,
list2.shuffle(); //but it won't changing radio option value when user click in it (i dont know why)
}
@override
Widget build(BuildContext context) {
print("---- BUILD ----");
return Container(
child: Column(
children: [
Text("${widget.qNumber}. ${widget.question}",style: TextStyle(
fontSize: 20,
),),
Builder(
//i actually didn't need this builder, but i used it just for checking variables
builder: (context){
print("---- BUILDER ----");
return Column(
children: option(),
);
},
)
],
),
);
}
}
这是我对你问题的第二个回答,第一个问题很简短,但在这里我解释一下我在第一个答案中的意思。我重写你的代码来回答你的问题。只需将其复制并粘贴到 DartPad 即可播放和测试。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Home(title: 'English Words Quiz'),
);
}
}
class Home extends StatelessWidget {
final String title;
const Home({Key? key, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: QuizTemplate(
model: QuizModel(
question: 'They cleaned _____ shoes.',
describe: 'Choose correct alternative',
questionNumber: 4,
answers: ['there', 'their', 'they´re', 'they'],
correctAnswer: 'their',
),
),
);
}
}
class QuizTemplate extends StatefulWidget {
const QuizTemplate({Key? key, required this.model}) : super(key: key);
final QuizModel model;
@override
State<QuizTemplate> createState() => _QuizTemplateState();
}
class _QuizTemplateState extends State<QuizTemplate> {
// The list outside of builder to avoid rebuilding.
late final List<String> _answers;
@override
void initState() {
_answers = widget.model.shuffled;
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ListTile(
leading: CircleAvatar(
child: Text(
'${widget.model.questionNumber}',
style: Theme.of(context).textTheme.headline5,
),
),
title: Text(
widget.model.question,
style: Theme.of(context).textTheme.headline5,
),
subtitle: widget.model.describe == null
? null
: Text(
widget.model.describe!,
style: Theme.of(context).textTheme.subtitle2,
),
),
for (final answer in _answers)
RadioListTile<int>(
title: Text(answer),
value: widget.model.indexOf(answer),
groupValue: widget.model.currentIndex,
onChanged: (index) {
setState(() {
widget.model.updateCurrentIndex(index);
});
},
),
if (widget.model.currentIndex != null)
Text(
widget.model.isCorrectAnswer
? 'The correct answer is ${widget.model.correctAnswer}'
: 'The answer is incorrect',
),
],
);
}
}
class QuizModel {
QuizModel({
required this.question,
required this.answers,
required this.correctAnswer,
this.describe,
this.questionNumber,
}) : assert(answers.isNotEmpty, "The answers can't be empty"),
assert(
answers.contains(correctAnswer),
'The answers must include correct answer, $correctAnswer is incorrect.',
);
final String question;
final String? describe;
final int? questionNumber;
final String correctAnswer;
final List<String> answers;
int? _currentIndex;
int? get currentIndex => _currentIndex;
List<String> get shuffled => answers..shuffle();
bool get isCorrectAnswer => indexOf(correctAnswer) == _currentIndex;
int indexOf(String answer) => answers.indexOf(answer);
void updateCurrentIndex(int? index) {
_currentIndex = index;
}
}
Dart 2.17 enhanced enum will be perfect for your situation and will make your code cleaner.
假设我想制作一个可以随机播放单选按钮选项的测验页面。
我已经尝试在初始状态下随机播放 List()(包含单选按钮),但它不起作用。单选按钮工作得很好,但它不会随机播放。这是我的清单
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
];
}
然后我使用我的第二个 tot 制作列表,但我将在 initState 中使用 listRadioOption() 对其进行初始化,如下所示:
late List<Widget> list2; //list for checking my second tot..
这是我的 initState :
@override
void initState() {
super.initState();
print("---- INIT STATE ----");
listRadioOption().shuffle(); //this doesn't shuffle the option, but radio option works perfectly
list2 = listRadioOption(); //this work if i use this as children,
list2.shuffle(); //but it won't changing radio option value when user click in it (i dont know why)
}
list2 可以很好地随机播放,但最终导致用户无法按单选按钮中的任何按钮。我的 listRadioOption() 工作正常,但不能随机播放。
我再次尝试使用这样的级联运算符:
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
]..shuffle();
}
它可以工作,但是当用户按下任何单选按钮时它会一直随机播放。 我对级联运算符略知一二,但是如果我像上面的代码那样在 return 语句中使用它意味着什么?
我想要的实际上只是随机播放单选按钮(1 次),单选按钮会根据用户的点击而改变
谁能帮帮我?
这是我的完整代码:
import 'package:flutter/material.dart';
enum ListJawaban{
answer1,
answer2,
answer3,
answer4,
answer5
}
class QuizTemplate extends StatefulWidget {
const QuizTemplate({
Key? key,
required this.question,
required this.option1,
required this.option2,
required this.option3,
required this.option4,
required this.option5,
required this.qNumber
}) : super(key: key);
final String question;
final String option1;
final String option2;
final String option3;
final String option4;
final String option5;
final int qNumber;
@override
State<QuizTemplate> createState() => _QuizTemplateState();
}
class _QuizTemplateState extends State<QuizTemplate> {
ListJawaban? _value = null;
Widget radioListTile({required String text, required ListJawaban jawaban}){
return RadioListTile<ListJawaban>(
title: Text("$text"),
value: jawaban,
groupValue: _value,
onChanged: (ListJawaban? newValue){
setState(() {
print("jawaban : $newValue");
_value = newValue;
});
},
);
}
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
];
}
late List<Widget> list2; //list for checking my second tot..
@override
void initState() {
super.initState();
print("---- INIT STATE ----");
listRadioOption().shuffle(); //this doesn't shuffle the option, but radio option works perfectly
list2 = listRadioOption(); //this work if i use this as children,
list2.shuffle(); //but it won't changing radio option value when user click in it (i dont know why)
}
@override
Widget build(BuildContext context) {
print("---- BUILD ----");
return Container(
child: Column(
children: [
Text("${widget.qNumber}. ${widget.question}",style: TextStyle(
fontSize: 20,
),),
Builder(
//i actually didn't need this builder, but i used it just for checking variables
builder: (context){
print("---- BUILDER ----");
listRadioOption().shuffle();
return Column(
children: listRadioOption(),
//children: list2,
);
},
)
],
),
);
}
}
更新
这是我的随机播放工作,但我无法更改值:
import 'package:flutter/material.dart';
enum ListJawaban{
answer1,
answer2,
answer3,
answer4,
answer5
}
class QuizTemplate extends StatefulWidget {
const QuizTemplate({
Key? key,
required this.question,
required this.option1,
required this.option2,
required this.option3,
required this.option4,
required this.option5,
required this.qNumber
}) : super(key: key);
final String question;
final String option1;
final String option2;
final String option3;
final String option4;
final String option5;
final int qNumber;
@override
State<QuizTemplate> createState() => _QuizTemplateState();
}
class _QuizTemplateState extends State<QuizTemplate> {
ListJawaban? _value = null;
Widget radioListTile({required String text, required ListJawaban jawaban}){
return RadioListTile<ListJawaban>(
title: Text("$text"),
value: jawaban,
groupValue: _value,
onChanged: (ListJawaban? newValue){
setState(() {
print("jawaban : $newValue");
_value = newValue;
});
},
);
}
List<Widget> listRadioOption(){
return [
//this should be shuffeled 1 time after build (in init state)
radioListTile(text: widget.option1, jawaban: ListJawaban.answer1),
radioListTile(text: widget.option2, jawaban: ListJawaban.answer2),
radioListTile(text: widget.option3, jawaban: ListJawaban.answer3),
radioListTile(text: widget.option4, jawaban: ListJawaban.answer4),
radioListTile(text: widget.option5, jawaban: ListJawaban.answer5),
];
}
late List<Widget> list2; //list for checking my second tot..
List<Widget> option(){
return list2;
}
@override
void initState() {
super.initState();
print("---- INIT STATE ----");
// listRadioOption().shuffle(); //this doesn't shuffle the option, but radio option works perfectly
list2 = listRadioOption(); //this work if i use this as children,
list2.shuffle(); //but it won't changing radio option value when user click in it (i dont know why)
}
@override
Widget build(BuildContext context) {
print("---- BUILD ----");
return Container(
child: Column(
children: [
Text("${widget.qNumber}. ${widget.question}",style: TextStyle(
fontSize: 20,
),),
Builder(
//i actually didn't need this builder, but i used it just for checking variables
builder: (context){
print("---- BUILDER ----");
return Column(
children: option(),
);
},
)
],
),
);
}
}
这是我对你问题的第二个回答,第一个问题很简短,但在这里我解释一下我在第一个答案中的意思。我重写你的代码来回答你的问题。只需将其复制并粘贴到 DartPad 即可播放和测试。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Home(title: 'English Words Quiz'),
);
}
}
class Home extends StatelessWidget {
final String title;
const Home({Key? key, required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: QuizTemplate(
model: QuizModel(
question: 'They cleaned _____ shoes.',
describe: 'Choose correct alternative',
questionNumber: 4,
answers: ['there', 'their', 'they´re', 'they'],
correctAnswer: 'their',
),
),
);
}
}
class QuizTemplate extends StatefulWidget {
const QuizTemplate({Key? key, required this.model}) : super(key: key);
final QuizModel model;
@override
State<QuizTemplate> createState() => _QuizTemplateState();
}
class _QuizTemplateState extends State<QuizTemplate> {
// The list outside of builder to avoid rebuilding.
late final List<String> _answers;
@override
void initState() {
_answers = widget.model.shuffled;
super.initState();
}
@override
Widget build(BuildContext context) {
return Column(
children: [
ListTile(
leading: CircleAvatar(
child: Text(
'${widget.model.questionNumber}',
style: Theme.of(context).textTheme.headline5,
),
),
title: Text(
widget.model.question,
style: Theme.of(context).textTheme.headline5,
),
subtitle: widget.model.describe == null
? null
: Text(
widget.model.describe!,
style: Theme.of(context).textTheme.subtitle2,
),
),
for (final answer in _answers)
RadioListTile<int>(
title: Text(answer),
value: widget.model.indexOf(answer),
groupValue: widget.model.currentIndex,
onChanged: (index) {
setState(() {
widget.model.updateCurrentIndex(index);
});
},
),
if (widget.model.currentIndex != null)
Text(
widget.model.isCorrectAnswer
? 'The correct answer is ${widget.model.correctAnswer}'
: 'The answer is incorrect',
),
],
);
}
}
class QuizModel {
QuizModel({
required this.question,
required this.answers,
required this.correctAnswer,
this.describe,
this.questionNumber,
}) : assert(answers.isNotEmpty, "The answers can't be empty"),
assert(
answers.contains(correctAnswer),
'The answers must include correct answer, $correctAnswer is incorrect.',
);
final String question;
final String? describe;
final int? questionNumber;
final String correctAnswer;
final List<String> answers;
int? _currentIndex;
int? get currentIndex => _currentIndex;
List<String> get shuffled => answers..shuffle();
bool get isCorrectAnswer => indexOf(correctAnswer) == _currentIndex;
int indexOf(String answer) => answers.indexOf(answer);
void updateCurrentIndex(int? index) {
_currentIndex = index;
}
}
Dart 2.17 enhanced enum will be perfect for your situation and will make your code cleaner.