I have a quiz screen where I am using an API
with FutureBuilder
. Each time build
method is refreshed, the new question is fetched. There's a submit button at the bottom to save the response and reset the screen. What I want to do is to disable
the submit button until new question is fetched after pressing the submit button and make enabled when new question is rebuild. I cannot call the setstate to make it null with a bool variable because new question is loaded due to this. Here's my code to reproduce the issue:
import 'package:flutter/material.dart';
class QuizForm extends StatefulWidget {
const QuizForm({Key? key}) : super(key: key);
@override
State<QuizForm> createState() => _QuizFormState();
}
class _QuizFormState extends State<QuizForm> {
int buildCount = 0 ;
getQuestion () {}
@override
Widget build(BuildContext context) {
print(buildCount);
print('Question Fetched and UI is building');
return SafeArea(child: Scaffold(
body: FutureBuilder(
future: getQuestion(),
builder: (context, snapshot){
return ListView(
children: [
ListTile(title: Text('Quiz Title'),),
ListTile(title: Text('1'),),
ListTile(title: Text('2'),),
ListTile(title: Text('3'),),
ListTile(title: Text('4'),),
SizedBox(height: 20,),
ElevatedButton(
onPressed: () async {
print('Please Wait, Answer is getting Saved');
// Button Should be shown disabled for 3 seconds
await Future.delayed(const Duration(seconds: 3));
buildCount ;
setState(() {
// this setState rebuilds the screen and new question is loaded
// because of future builder
});
}, child: Text('Submit Quiz'))
],
);
},
),
));
}
}
CodePudding user response:
When you are getting data from API check if you have data in your variable , if has data return data if not then call API ,
update : with _submitEnabled value .
Here example :
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class QuizForm extends StatefulWidget {
const QuizForm({Key? key}) : super(key: key);
@override
State<QuizForm> createState() => _QuizFormState();
}
class _QuizFormState extends State<QuizForm> {
Question _cachedQuestion;
bool _submitEnabled = false;
Future<Question> getQuestion() async {
if (_cachedQuestion != null) {
return _cachedQuestion;
}
final response = await http.get('https://your-api-endpoint.com/question');
if (response.statusCode == 200) {
final question = Question.fromJson(json.decode(response.body));
_cachedQuestion = question;
_submitEnabled = true;
return question;
} else {
throw Exception('Failed to fetch question');
}
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: FutureBuilder(
future: getQuestion(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final question = snapshot.data;
return ListView(
children: [
ListTile(title: Text(question.title)),
ListTile(title: Text(
CodePudding user response:
I managed to get it through ValueListenableBuilder
. Here is my code that is working as expected:
import 'package:flutter/material.dart';
class QuizForm extends StatefulWidget {
const QuizForm({Key? key}) : super(key: key);
@override
State<QuizForm> createState() => _QuizFormState();
}
class _QuizFormState extends State<QuizForm> {
final _buttonEnabled = ValueNotifier(true);
int buildCount = 0;
getQuestion () {}
@override
Widget build(BuildContext context) {
print(buildCount);
return SafeArea(
child: Scaffold(
body: FutureBuilder(
future: getQuestion(),
builder: (context, snapshot) {
return ListView(
children: [
ListTile(title: Text('Quiz Title')),
ListTile(title: Text('1')),
ListTile(title: Text('2')),
ListTile(title: Text('3')),
ListTile(title: Text('4')),
SizedBox(height: 20),
ValueListenableBuilder(
valueListenable: _buttonEnabled,
builder: (context, value, child) {
return ElevatedButton(
onPressed: _buttonEnabled.value
? () async {
_buttonEnabled.value = false;
print('Please Wait, Answer is getting Saved');
await Future.delayed(const Duration(seconds: 3));
_buttonEnabled.value = true;
buildCount ;
setState(() {
});
}
: null,
child: child,
);
},
child: Text('Submit Quiz'),
),
],
);
},
),
),
);
}
}