Reputation: 189
So I'm building this really simple question and answer app, where the screen displays a question and a list of answers in a RadioTileWidget, by swiping a user can see more questions and answers. I used flutter_swipper to achieve changing the questions and answers when swiped. My issue now is that after selecting a particular answer and I swipe to the next question the radio button is still at the position I selected. Obviously, this isn't right. so is there a way I can refresh the state of the RadioListTile after I swipe, but keeping the state of the previously selected answer?
My code:
class QuestionScreen extends StatefulWidget {
@override
_QuestionScreenState createState() => _QuestionScreenState();
}
class _QuestionScreenState extends State<QuestionScreen> {
late SwiperController _controller;
int ?value;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = SwiperController();
}
@override
Widget build(BuildContext context) {
return BaseView(
body: Column(
children: [
// This is the question and answer container
Container(
height: 80.h,
width: 100.w,
child: Swiper(
loop: false,
controller: _controller,
itemBuilder: (BuildContext context, int mainIndex) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// This is the question conatiner
Container(
width: 100.w,
child: Center(
child: Text(
'(${mainIndex+1}) ${questions[mainIndex]['question']}')),
),
// This is the answer container
Container(
height: 50.h,
child: ListView.builder(
itemBuilder: (context, index) {
var ans = questions[mainIndex]['answers'];
var _ = ans.keys.toList()[index];
var _v = ans.values.toList()[index];
return RadioListTile(
value: index,
groupValue: value,
onChanged: (newVal) =>
setState(() => value = newVal as int),
title: Text('$_ : $_v'),
);
},
itemCount: questions[mainIndex]['answers'].length,
),
),
],
);
},
itemCount: questions.length,
pagination: new SwiperPagination(),
),
),
// container that holds the previous and Next buttons
Container(
// color: Colors.black,
// height: 20.h,
width: 100.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
_controller.previous();
},
child: Text('Prev'),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(AppColors.brown)),
),
TextButton(
onPressed: () {
_controller.next();
},
child: Text('Next'),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(AppColors.brown),
),
),
],
))
],
),
);
}
}
So that's it. If there's some part of my explanation that's not understood please do ask me. Thanks in advance.
Upvotes: 1
Views: 310
Reputation: 189
After a while, I realized the solution wasn't that far-fetched. I used a List to store the value/state of each radio button on each page that I swiped to.
What I did: I created a list with fixed length (length of the number of questions I had)
late List<dynamic> _stateList;
@override
void initState() {
super.initState();
\\
_stateList = List<dynamic>.filled(questions.length, '',
growable:
false); // on initializing list the list looks like this ['', '', '']
}
Then I changed RadioListTile like so:
return RadioListTile<String>(
value: _,
groupValue: _stateList[mainIndex].toString(),
onChanged: (newVal) => setState(() {
// value = newVal;
_stateList[mainIndex] =
newVal; // assign new value to the _stateList[mainIndex]
print(_stateList[mainIndex]);
}),
title: Text('$_ : $_v'),
);
That's all I did.
What I just did was store the user's selected value for each page generated. mainIndex
is the index of the page generated by Swiper, so for each mainIndex store a value for the answer selected.
Full code:
class QuestionScreen extends StatefulWidget {
@override
_QuestionScreenState createState() => _QuestionScreenState();
}
class _QuestionScreenState extends State<QuestionScreen> {
late SwiperController _controller;
late List<dynamic>
_stateList; // to store state for radioSelection for each answered questiion
String? value;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = SwiperController();
_stateList = List<dynamic>.filled(questions.length, '',
growable:
false); // on initializing list the list looks like this ['', '', '']
}
/*
Note to self: The _stateList created is to store the value of radio button (for each specific question) and hold
the answer picked by the user
*/
@override
Widget build(BuildContext context) {
return BaseView(
body: Column(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: 80.h,
width: 100.w,
child: Swiper(
loop: false,
controller: _controller,
itemBuilder: (BuildContext context, int mainIndex) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// question
Container(
// height: 50.h,
width: 100.w,
child: Center(
child: Text(
'(${mainIndex + 1}) ${questions[mainIndex]['question']}')),
),
// answer
Container(
height: 50.h,
child: ListView.builder(
itemBuilder: (context, index) {
var ans = questions[mainIndex]['answers'];
var _ = ans.keys.toList()[index];
var _v = ans.values.toList()[index];
return RadioListTile<String>(
value: _,
groupValue: _stateList[mainIndex].toString(),
onChanged: (newVal) => setState(() {
// value = newVal;
_stateList[mainIndex] =
newVal; // assign new value to the _stateList[mainIndex]
print(_stateList[mainIndex]);
}),
title: Text('$_ : $_v'),
);
},
itemCount: questions[mainIndex]['answers'].length,
),
),
],
);
},
itemCount: questions.length,
// itemWidth: 300.0,
// itemHeight: 400.0,
pagination: new SwiperPagination(),
// control: new SwiperControl(),
),
),
//
Container(
// color: Colors.black,
// height: 20.h,
width: 100.w,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {
_controller.previous();
// setState(() {
// });
},
child: Text('Prev'),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(AppColors.brown)),
),
TextButton(
onPressed: () {
_controller.next();
},
child: Text('Next'),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(AppColors.brown),
),
),
],
))
],
),
);
}
}
Upvotes: 1