Reputation: 173
I'm using Flutter-Dart-SQLite to develop a quiz application. Here I have used RadioListTile for radio button functionality. I am passing the text value from an array to this StatefulWidget
.
This is the code I'm using,
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();
}
}
Here the selectedButton which is null initially takes place of value of group value after onChanged
. Now, I need to clear the selected button when the other button is clicked.
I'm guessing I have something done wrong in group value part.
The part where I use 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) {}
}
I get values from an array where the options are separated by comma. "Answer":"Male,Female"
Upvotes: 6
Views: 17372
Reputation: 91
1) Firstly define Boolean in the class.
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) Then use the Ternary operator.
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")
],
),
Upvotes: 0
Reputation: 3514
This is happening because you are defining individual groupValue
for each Radio button. Rather than defining selectedButton
field for each button define it once in that file where you are calling this widget
and pass the value
through it's constructor
like below code :
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);
}
and use this value
and press
function to your Radio button like this :
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,
)
also pass ValueChanged(Object)
in place of VoidCallBack
:
final ValueChanged<Object> press;
and pass a proper function there like :
OptionRadio(
text: "abc",
index: index,
press: (val) => setState(() {
selectButton = int.parse(val.toString());
print("$selectButton");
}),
selectButton: selectButton,
)
Upvotes: 1
Reputation: 7502
Here is sample code by using your 'OptionRadioPage' Widget.
(but some code deleted because of leak of code)
As I commented, 'groupValue' should shared with two 'OptionRadioPage' widgets.
So I store that value 'OptionRadioPage' parent widget and
also pass the that value to 'OptionRadioPage' widgets.
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,
),
]),
)),
),
],
),
),
);
}
}
Upvotes: 3