setState() not working properly in flutter - flutter

I have a question palette in the flutter screen, where a user taps on the question number that question is shown, and a next button to display the next question.
If I am traversing between the questions using the question palette it's working fine but when I click next button, it does not turn the question number on the palette to green(I want that question number to get green) and also it does not return the next question but the loop iterates. As after I press the button for some time, it says that there are no next questions as I have set this message when the loop ends.
Here is my code:
class quizpage extends StatefulWidget{
var questions,surveyid;
quizpage(this.questions,this.surveyid);
//quizpage({Key key, #required this.questions}) : super(key : key);
#override
_quizpageState createState() => _quizpageState(questions,surveyid);
}
class _quizpageState extends State<quizpage> with SingleTickerProviderStateMixin {
var questions,surveyid;
_quizpageState(this.questions,this.surveyid);
int i = 0;
int flag = 0;
int counter = 0;
int length;
Map<String, Color> btncolor = {
"1" : Colors.grey,
"2" : Colors.grey,
"3" : Colors.grey,
"4" : Colors.grey,
"5" : Colors.grey,
"6" : Colors.grey,
"7" : Colors.grey,
"8" : Colors.grey,
"9" : Colors.grey,
};
final answercontroller = TextEditingController();
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitDown, DeviceOrientation.portraitUp
]);
SizeConfig().init(context);
// TODO: implement build
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SizedBox(
height: 600,
child: Column(
children: <Widget>[
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Numberofquestion()
],
),
),
Expanded(
flex: 4,
child: Center(
child: Container(
width: 400,
height: 400,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: 250,
child: Material(
elevation: 5,
color: Colors.deepOrange,
borderRadius: BorderRadius.all(
Radius.circular(10.0)),
child: TextField(
enabled: false,
maxLines: 6,
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
hintText: questions[i]
),
style: TextStyle(
fontSize: 20,
color: Colors.black
),
),
),
)
],
),
),
)
),
Expanded(
flex: 2,
child: Center(
child: Container(
width: 300,
height: 300,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: 250,
child: Material(
elevation: 2,
color: Colors.deepOrange,
borderRadius: BorderRadius.all(
Radius.circular(10.0)),
child: TextField(
controller: answercontroller,
maxLines: 1,
//enabled: false,
decoration: InputDecoration(
fillColor: Colors.white,
filled: true,
hintText: 'Answer'
),
style: TextStyle(
fontSize: 20,
color: Colors.black
),
),
),
),
]
)
)
)
),
Expanded(
flex: 2,
child: Align(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(onPressed: SkipQuestion,
color: Colors.deepOrange,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
child: Text('Skip',
style: TextStyle(
fontSize: 20
),
),
),
RaisedButton(onPressed: NextQuestion,
color: Colors.green,
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
child: Text('Next',
style: TextStyle(
fontSize: 20
),
),
),
],
),
],
),
)
)
],
),
),
),
),
);
}
#override
void setState(fn) {
// TODO: implement setState
super.setState(fn);
if(btncolor[(i+1).toString()] == Colors.deepOrange){
btncolor[(i+1).toString()] = Colors.purple;
flag = 1;
}
else if(btncolor[(i+1).toString()] == Colors.green){
btncolor[(i+1).toString()] = Colors.purple;
flag = 2;
}
else{
btncolor[(i+1).toString()] = Colors.purple;
}
}
void NextQuestion() async {
if(answercontroller.text.length == 0){
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Alert'),
content: Text(
'Please enter an answer.'),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop(); // dismisses only the dialog and returns nothing
},
child: new Text('OK'),
),
],
),
);
}
else{
setState(() async {
if(i < (questions.length - 1)){
// ignore: unnecessary_statements
btncolor[(i+1).toString()] = Colors.green;
i++;
}
else{
await showDialog(
context: context,
builder: (context) => new AlertDialog(
title: new Text('Alert'),
content: Text(
'There are no next questions.'),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context, rootNavigator: true)
.pop(); // dismisses only the dialog and returns nothing
},
child: new Text('OK'),
),
],
),
);
}
});
}
}
#override
void initState() {
SystemChrome.setEnabledSystemUIOverlays([]);
super.initState();
}
void SkipQuestion() {
setState(() {
if(i < (questions.length - 1)){
// ignore: unnecessary_statements
btncolor[(i+1).toString()] = Colors.deepOrange;
i++;
}
else{
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(surveyid),
));
}
});
}
void ChooseQuestion() {
setState(() {
if(i < (questions.length)){
for(int k =0; k< (questions.length); k++){
if(k != i){
if(btncolor[(k+1).toString()] == Colors.purple){
if(flag == 1){
btncolor[(k+1).toString()] = Colors.red;
flag =0;
}
else if(flag == 2){
btncolor[(k+1).toString()] = Colors.green;
flag =0;
}
else{
btncolor[(k+1).toString()] = Colors.grey;
}
}
}
else{
if(btncolor[(k+1).toString()] == Colors.purple){
if(flag == 1){
btncolor[(k+1).toString()] = Colors.red;
}
else if(flag == 2){
btncolor[(k+1).toString()] = Colors.green;
flag =0;
}
else{
btncolor[(k+1).toString()] = Colors.grey;
}
}
}
}
//i++;
}
else{
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(surveyid),
));
}
});
}
Widget Numberofquestion() {
if(questions.length == 9){
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: 40,
padding: EdgeInsets.all(5),
child: RaisedButton(onPressed: () {
i = 0;
ChooseQuestion();
},
color: btncolor["1"],
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
child: Text("1",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20
),
),
),
),
Container(
width: 40,
padding: EdgeInsets.all(5),
child: RaisedButton(onPressed: () {
i = 1;
ChooseQuestion();
},
color: btncolor["2"],
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
child: Text('2',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20
),
),
),
),
Container(
width: 40,
padding: EdgeInsets.all(5),
child: RaisedButton(onPressed: () {
i = 2;
ChooseQuestion();
},
color: btncolor["3"],
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
child: Text('3',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20
),
),
),
),
Container(
width: 40,
padding: EdgeInsets.all(5),
child: RaisedButton(onPressed: () {
i = 3;
ChooseQuestion();
},
color: btncolor["4"],
textColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0))),
child: Text('4',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20
),
),
),
),
],
);
}
}
}
Here, questions is the array which stores the question.
When I am using the 'Skip' button, the setState works perfectly but when I am using 'Next' button the setState is not working.
Can someone help me with this please?

I'd say that you're manipulating the state in a wrong way
As docs refers:
#protected
void setState (VoidCallback fn)
The provided callback is immediately called synchronously. It must not return a future (the callback cannot be async), since then it would be unclear when the state was actually being set.
things to note:
don't call setState() inside initState()
don't call setState() in synchronous code inside build()
setState() should run synchronously so new updates happen atomically
hence, try not to mark setState() as async
You might see the link, hope it's useful

try this
#override
void setState(fn) {
if(btncolor[(i+1).toString()] == Colors.deepOrange){
btncolor[(i+1).toString()] = Colors.purple;
flag = 1;
}
else if(btncolor[(i+1).toString()] == Colors.green){
btncolor[(i+1).toString()] = Colors.purple;
flag = 2;
}
else{
btncolor[(i+1).toString()] = Colors.purple;
}
super.setState(fn);//move here
}

Related

Flutter - ScrollController was used after being disposed

class HomeScreen extends StatefulWidget {
final userName;
HomeScreen(this.userName);
#override
State<HomeScreen> createState() => _HomeScreenState();
}
Future<ClientDashboardModel?>? _meterReadingResponse;
BatchSummaryModel? _batchResponse;
AMRDashboardModel? _amrDashboardResponse;
String _userName = '';
int? qcAssignedReads = 0;
int? qcMrCompleted = 0;
int? qcCompletedReads = 0;
int? qcPendingReads = 0;
int? qcApprovedReads = 0;
int? qcRejectedReads = 0;
bool isFirstTimeCalled = false;
Timer? _timer;
int _currentIndex = 0;
final pages = [
const MDMScreen(),
const AMRDashboard(whichScreen: 0),
const AMRDashboard(whichScreen: 1),
const AMRDashboard(whichScreen: 2)
];
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
setUpTimedFetch();
super.initState();
if (widget.userName != null) _userName = (widget.userName!);
}
#override
void dispose() {
isFirstTimeCalled = false;
_timer?.cancel();
super.dispose();
}
void setUpTimedFetch() {
if (!isFirstTimeCalled) {
_meterReadingResponse = _getDashboardData();
}
isFirstTimeCalled = true;
}
Future<ClientDashboardModel?> _getDashboardData() async {
ClientDashboardModel? meterReadingResponse;
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
var responseData = await Dashboard().getClientDashboard(token);
if (responseData.statusCode == 200) {
String data = responseData.body;
var decodedData = jsonDecode(data);
meterReadingResponse = null;
meterReadingResponse = ClientDashboardModel.fromJson(decodedData);
return meterReadingResponse;
}
return null;
}
void logout() async {
SharedPreferences.getInstance().then((value) {
value.remove('token');
value.remove('userName');
});
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) {
return const LoginScreen();
}));
}
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: const Text(Strings.kLogoutLabel),
content: const Text(Strings.kConfirmLogout),
actions: <Widget>[
TextButton(
child: const Text(Strings.kCancelLabel),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text(Strings.kOKLabel),
onPressed: () {
Navigator.of(context).pop();
logout();
},
)
],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
backgroundColor: const Color(0XFF116AFF),
unselectedItemColor: Colors.white,
selectedLabelStyle: const TextStyle(color: Colors.white),
showUnselectedLabels: false,
onTap: (value) {
setState(() => _currentIndex = value);
},
items: [
BottomNavigationBarItem(
label: 'MDM',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 0 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.electric_meter_outlined),
),
),
),
BottomNavigationBarItem(
label: 'Site Survey',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 1 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.location_city_outlined),
),
),
),
BottomNavigationBarItem(
label: 'Meter Replace',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 2 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.library_books_outlined),
),
),
),
BottomNavigationBarItem(
label: 'TroubleShoot',
icon: Container(
decoration: BoxDecoration(
color:
_currentIndex == 3 ? Colors.white : Colors.transparent,
shape: BoxShape.circle),
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Icon(Icons.info_outline),
),
),
),
],
),
appBar: AppBar(
automaticallyImplyLeading: false,
title: const Text(Strings.kMRDLabel),
actions: [
IconButton(
onPressed: () {
_showMyDialog();
},
icon: const Icon(Icons.power_settings_new))
],
),
body: childView());
}
Widget childView() {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
Strings.kWelcome2Label,
style: TextStyle(
color: Colors.amber.shade700,
fontSize: 16.0,
fontWeight: FontWeight.w600),
),
Text(
_userName.toTitleCase(),
style: const TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.w400),
)
],
),
const Spacer(),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(color: Colors.grey.shade200),
child: SvgPicture.asset(
'images/profile.svg',
height: 54.0,
width: 54.0,
),
),
),
],
),
const SizedBox(
height: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [pages[_currentIndex]],
),
],
),
));
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:manager/components/dotted_line.dart';
import 'package:manager/model/lookup_cycle.dart';
import 'package:manager/model/mr_report_model.dart';
import 'package:manager/services/dashboard_service.dart';
import 'package:manager/utils/debouncer.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:manager/utils/string_captialize.dart';
class MRPerformance extends StatefulWidget {
const MRPerformance({super.key});
#override
State<MRPerformance> createState() => _MRPerformanceState();
}
bool isFilter = false;
bool isPerformingRequest = false;
int pageNumber = 0;
String _chosenValue = '';
List<MRReportResult> users = [];
Future<List<String>?>? dropDownValue;
ScrollController _scrollController = ScrollController();
final _debouncer = Debouncer(milliseconds: 500);
class _MRPerformanceState extends State<MRPerformance> {
#override
void initState() {
super.initState();
_getMoreData(_chosenValue);
dropDownValue = getAllCategory();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
_getMoreData(_chosenValue);
}
});
}
Future<List<String>?>? getAllCategory() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
var cycleResponse = await Dashboard().getAllCycle(token);
try {
if (cycleResponse.statusCode == 200) {
List<String> items = [];
var jsonData = json.decode(cycleResponse.body) as List;
List<LookUpCycle> lookupCycle = jsonData
.map<LookUpCycle>((json) => LookUpCycle.fromJson(json))
.toList();
items.add('Select');
for (var element in lookupCycle) {
if (element.name != null) {
items.add(element.name!);
}
}
return items;
}
} catch (ex) {
throw (ex.toString());
}
return null;
}
#override
void dispose() {
super.dispose();
_scrollController.dispose();
}
void _getMoreData(String searchCycle) async {
List<MRReportResult>? resultResponse = [];
if (!isPerformingRequest) {
setState(() {
isPerformingRequest = true;
});
SharedPreferences prefs = await SharedPreferences.getInstance();
String token = prefs.getString('token')!;
debugPrint(token);
var responseData =
await Dashboard().getMRReport(token, pageNumber, 10, searchCycle);
if (responseData.statusCode == 200) {
String data = responseData.body;
var decodedData = jsonDecode(data);
MRReportModel newEntries = MRReportModel.fromJson(decodedData);
if (newEntries.result == null) {
if (newEntries.result!.isEmpty) {
double edge = 50.0;
double offsetFromBottom =
_scrollController.position.maxScrollExtent -
_scrollController.position.pixels;
if (offsetFromBottom < edge) {
_scrollController.animateTo(
_scrollController.offset - (edge - offsetFromBottom),
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut);
}
}
}
setState(() {
users.addAll(newEntries.result!);
isPerformingRequest = false;
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: const Text('MR Performance')),
body: filterView());
}
void setFilterState() {
setState(() {
if (isFilter == true) {
isFilter = false;
} else {
isFilter = true;
}
});
}
Widget _buildProgressIndicator() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Opacity(
opacity: isPerformingRequest ? 1.0 : 0.0,
child: const CircularProgressIndicator(),
),
),
);
}
Widget filterView() {
return Column(
children: [
Row(
children: [
Visibility(
visible: isFilter ? true : false,
child: Flexible(
child: Card(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
elevation: 2,
child: Column(
children: [
Row(
children: [
Expanded(
child: TextField(
textInputAction: TextInputAction.search,
decoration: const InputDecoration(
border: InputBorder.none,
prefixIcon: InkWell(
child: Icon(Icons.search),
),
contentPadding: EdgeInsets.all(8.0),
hintText: 'Search ',
),
onChanged: (string) {
_debouncer.run(() {});
},
),
),
],
),
],
),
),
),
),
Visibility(
visible: isFilter ? false : true,
child: Flexible(
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.only(
left: 10,
),
child: FutureBuilder<List<String>?>(
future: dropDownValue,
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Something wrong');
} else if (snapshot.hasData) {
var data = snapshot.data!;
return DropdownButtonHideUnderline(
child: DropdownButton<String>(
icon: const Icon(
Icons.expand_more_outlined,
size: 35,
color: Color(0XFF116AFF),
),
borderRadius: BorderRadius.circular(10),
isExpanded: true,
// value: _chosenValue.isNotEmpty ? _chosenValue : null,
elevation: 16,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400),
items: data.map((String value) {
return DropdownMenuItem(
value: value, child: Text(value));
}).toList(),
hint: Padding(
padding: const EdgeInsets.all(15),
child: Text(
_chosenValue.isEmpty
? 'Cycle'
: _chosenValue,
style: const TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w400),
),
),
onChanged: (String? value) {
setState(() {
if (value != null) {
pageNumber = 0;
users.clear();
if (value == 'Select') {
_chosenValue = '';
} else {
_chosenValue = value;
}
_getMoreData(_chosenValue);
}
});
},
),
);
}
}
return const CircularProgressIndicator();
},
)),
),
),
),
InkWell(
onTap: () => {setFilterState()},
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: isFilter
? const Icon(Icons.filter_alt, color: Color(0XFF116AFF))
: const Icon(
Icons.search,
color: Color(0XFF116AFF),
),
),
),
),
],
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: users.length + 1,
controller: _scrollController,
itemBuilder: (BuildContext context, int index) {
if (index == users.length) {
return _buildProgressIndicator();
} else {
return cardView(users, index);
}
}),
),
],
);
}
Widget cardView(List<MRReportResult>? users, int index) {
return Card(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0XFFDCDCDC)),
borderRadius: BorderRadius.circular(10)),
margin: const EdgeInsets.all(8),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(
color: Colors.orange,
),
borderRadius: const BorderRadius.all(Radius.circular(20))),
margin: const EdgeInsets.all(10),
padding: const EdgeInsets.all(10),
child: Row(
children: [
Text(
'${users?[index].mRNumber}: ',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
Text(
'${users?[index].meterReaderName}'.toTitleCase(),
style: const TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.w400),
),
],
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Row(
children: [
const Text(
'Supervisor: ',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 10,
fontWeight: FontWeight.w600),
),
Expanded(
child: Text(
'${users?[index].supervisor}'.toTitleCase(),
overflow: TextOverflow.fade,
style: const TextStyle(
color: Colors.black,
fontSize: 10,
fontWeight: FontWeight.w400),
),
),
],
),
),
const SizedBox(height: 10),
const MySeparator(),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Column(
children: [
Text(
'${users?[index].unreadPercenatge}%',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'Unread',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].readPercenatge}%',
style: const TextStyle(
color: Colors.green,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'Read',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].plusorMinusTwoReadPercentage}%',
style: const TextStyle(
color: Colors.green,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'+/- 2',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
Row(
children: [
Column(
children: [
Text(
'${users?[index].above32ReadPercentage}%',
style: const TextStyle(
color: Colors.orange,
fontSize: 10,
fontWeight: FontWeight.w600),
),
const Text(
'>32',
style: TextStyle(
color: Color(0XFF004AC6),
fontSize: 12,
fontWeight: FontWeight.w400),
)
],
)
],
),
],
),
),
],
),
),
);
}
}
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Builder:
A ScrollController was used after being disposed.
Once you have called dispose() on a ScrollController, it can no longer be used.
The relevant error-causing widget was
MaterialApp
lib/main.dart:13
When the exception was thrown, this was the stack
You have declared _getMoreData two times in init(), so remove it before _scrollController as shown below
void initState() {
super.initState();
_getMoreData(_chosenValue);-------------> remove this from here
dropDownValue = getAllCategory();
_scrollController.addListener(() {
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
pageNumber++;
_getMoreData(_chosenValue);
}
});
}
OR
Declare ScrollController _scrollController = ScrollController(); in state class _MRPerformanceState as below code:
class _MRPerformanceState extends State<MRPerformance> {
ScrollController _scrollController = ScrollController();

setState() on showDialog() from initState() is not changing the state. Flutter

I have created a dialog with StatefulBuilder. Setstate works perfectly within the StatefulBuilder. But I want to change that state from initstate too. But the set state from initstate is not called.
My code:
#override
void initState() {
super.initState();
rest_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 15),
);
rest_controller.addListener(() {
if (rest_controller.isAnimating) {
setState(() {
print("rp"+rest_progress.toString());
rest_progress = rest_controller.value;
});
} else {
setState(() {
print("rp2"+rest_progress.toString());
rest_progress = 1.0;
rest_isPlaying = false;
});
}
});
}
Dialog open function:
showDataAlert() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(
20.0,
),
),
),
backgroundColor: kMainColor,
contentPadding: EdgeInsets.only(
top: 10.0,
),
title: Text(
"Take Rest",
style: TextStyle(fontSize: 24.0, color: kTextColor),
),
content:
Center(
child: Column(
children: [
SizedBox(
height: 10,
),
Expanded(
child: Stack(
alignment: Alignment.center,
children: [
SizedBox(
width: 260,
height: 260,
child: CircularProgressIndicator(
backgroundColor: Colors.grey.shade300,
value: rest_progress,
strokeWidth: 6,
),
),
AnimatedBuilder(
animation: rest_controller,
builder: (context, child) => Text(
restCountText,
style: TextStyle(
fontSize: 50,
fontWeight: FontWeight.bold,
color: kTextColor,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () {
if (rest_controller.isAnimating) {
rest_controller.stop();
setState(() {
rest_isPlaying = false;
});
} else {
rest_controller.reverse(from: rest_controller.value == 0 ? 1.0 : rest_controller.value);
setState(() {
rest_isPlaying = true;
});
}
},
child: RoundButton(
icon: rest_isPlaying == true ? Icons.pause : Icons.play_arrow,
),
),
GestureDetector(
onTap: () {
rest_controller.reset();
setState(() {
rest_isPlaying = false;
});
},
child: RoundButton(
icon: Icons.stop,
),
),
],
),
)
],
),
),
);
}
);
});
}
Basically, setstate from the initstate is not changing the state. I have tried to change the state from showDataAlert function also, but no luck. Only the state changes if I click the button inside the showdialog.

How to remove build side effects in this context, using Staggered Grid View Builder Flutter?

I am trying to create the build method without side effects (without blinking). I solved this problem using StatefulBuilder, but I read that I should rebuild 1000x times without any change or effect.
The Staggered Grid View Builder Widget are rebuilt when the keyboard is opening, or whenever I open again the page, or add/remove an item from it. That's good, normally, but with side effects like you see below. Maybe there is any solution to animate the remove/add functionality, or the infinite reloading and keep the rest of the items in cache. So I need to limit the builder recreate inside Grid View Builder?
On other applications I don't see this ugly "blinking". Where is the problem and how can I solve it? I used Animation Limiter but it's not working for me, neither PrecacheImage, somehow I need to rebuild without blink (first items).
My code:
class VisionBoard extends StatefulWidget {
const VisionBoard({Key? key}) : super(key: key);
#override
_VisionBoardState createState() => _VisionBoardState();
}
class _VisionBoardState extends State<VisionBoard> with SingleTickerProviderStateMixin {
ScreenshotController screenshotController = ScreenshotController();
String saveGoalsButtonText = "SAVE GOALS";
String wallpaperButtonText = "CREATE WALLPAPER";
String saveWallpaperButtonText = "SAVE";
bool createWallpaper = false;
bool isWallpaperCreated = false;
late File imageFile;
late String newImage;
late Uint8List imageRaw;
int noOfImages = 0;
late Uint8List wallpaperBytes;
String title = "My Vision Board";
String goals = "";
late List<String> visions = <String>[];
final TextEditingController _textFieldController = TextEditingController();
final TextEditingController _goalsController = TextEditingController();
static final _formKey = GlobalKey<FormState>();
#override
void initState() {
super.initState();
loadVisionBoardTitleAndImages();
}
void loadVisionBoardTitleAndImages() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//await prefs.clear();
setState(() {
_textFieldController.text = prefs.getString('titlu') ?? title;
visions = prefs.getStringList('visions') ?? <String>[];
_goalsController.text = prefs.getString('goals') ?? goals;
});
}
void _removeVisions(int index) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
isButtonDisabled=true;
visions.removeAt(index);
prefs.setStringList('visions', visions);
createWallpaper = false;
wallpaperButtonText = "CREATE WALLPAPER";
isWallpaperCreated = false;
});
await CreateWallpaperLayouts().createWallpaper(visions).then((value) {
setState(() {
wallpaperBytes = value;
wallpaper = Image.memory(wallpaperBytes);
precacheImage(wallpaper.image, context);
isButtonDisabled=false;
});
});
}
#override
Widget build(BuildContext context) {
return Sizer(
builder: (context, orientation, deviceType) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
child: Scaffold(
body: AnimationLimiter(
child: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/background-marmura.jpeg"), fit: BoxFit.cover)),
child: SafeArea(
child: SingleChildScrollView(
child: Container(
margin: const EdgeInsets.fromLTRB(20, 0, 20, 0),
child: Column(
children: [
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Row(
children: [
Flexible(
child: Text(_textFieldController.text,
style: const TextStyle(
fontWeight: FontWeight.w700,
fontSize: 21,
color: Color(0xff393432),
),
),
),
IconButton(
icon: const Icon(
Icons.edit,
size: 21,
color: Color(0xff393432),
),
onPressed: () {
showAlertDialog(context, setState);
},
)
]);
}
),
const SizedBox(height: 5),
GridView.builder(
clipBehavior: Clip.none,
physics: const ScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: SizeConfig.screenWidth!/3,),
itemCount: (visions.length == 12) ? visions.length : visions.length + 1,
itemBuilder: (BuildContext ctx, index) {
if (index < visions.length) {
return AnimationConfiguration.staggeredGrid(
position: index,
duration: const Duration(milliseconds: 1000),
columnCount: 3,
child: ScaleAnimation(
child: FadeInAnimation(
child: OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: index < visions.length, //bind with the boolean
child: Stack(
alignment: Alignment.center,
children: [
Container(
width: 25.w,
height: 25.w,
decoration: BoxDecoration(
image: DecorationImage(
image: CleverCloset.imageFromBase64String(visions[index]).image,
fit: BoxFit.fill),
borderRadius: const BorderRadius.all(
Radius.circular(
5.0) // <--- border radius here
),
),
),
Positioned(
top:0,
right:0,
child: ClipOval(
child: InkWell(
onTap: () {
_removeVisions(index);
},
child: Container(
padding: const EdgeInsets.all(5),
color: Colors.white,
child:
const Icon(
Icons.delete,
size: 16,
color: Color(0xff393432)),
),
),
),
),
],
clipBehavior: Clip.none,
),
),
),
),
);
}
else if(index<12){
return InkWell(
onTap: () {
_openGallery(context);
},
child:
Stack(
alignment: Alignment.center,
children:[
Container(
width: 25.w,
height: 25.w,
decoration:
BoxDecoration(
border: Border.all(color: const Color(0xff393432)),
borderRadius: const BorderRadius.all(Radius.circular(5.0)),
),
child:
const Icon(
Icons.add,
size: 25,
color: Color(0xff393432),
)
),
],
),
);
}
else {
return Container(color: Colors.red);
}
}
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Text("You can add up to 12 pictures.",
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w400,
fontStyle: FontStyle.italic,
),),
],
),
const SizedBox(height: 10),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column (
children: [
if(visions.isNotEmpty && visions.length>1 && !isWallpaperCreated) Row(
children: [
SizedBox(
width: 50.w,
child: OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value)
enabled: !isWallpaperCreated &&
visions.isNotEmpty && visions.length > 1,
child: OutlinedButton(
onPressed: visions.isNotEmpty &&
visions.length > 1 ? () async{
setState(() {
wallpaperButtonText = "CREATING...";
//_createWallpaper();
});
wallpaperBytes = await CreateWallpaperLayouts().createWallpaper(visions);
setState(() {
noOfImages = visions.length;
isWallpaperCreated = true;
createWallpaper = true;
});
//Navigator.pushReplacementNamed(context, '/masterclasses');
} : null,
style: OutlinedButton.styleFrom(
primary: const Color(0xffE4BCB4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
18.0),
),
side: const BorderSide(
width: 3, color: Color(0xffE4BCB4)),
),
child: Text(
wallpaperButtonText,
style: const TextStyle(
color: Color(0xff393432),
fontSize: 14,
fontWeight: FontWeight.w700,
)
),
),
),
),
],
),
const SizedBox(height:40),
if(createWallpaper==true) OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: createWallpaper, //bind with the boolean
child: Row(
children: const [
Flexible(
child: Text("Wallpaper",
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 21,
color: Color(0xff393432),
),
),
),
],
),
),
if(createWallpaper==true) const SizedBox(height:15),
if(createWallpaper==true)
OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: createWallpaper,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children:[ Container(
width: 50.w,//double.infinity,
height: 50.h,//SizeConfig.screenHeight,
decoration: BoxDecoration(
image: DecorationImage(
image: Image.memory(wallpaperBytes).image,
fit: BoxFit.fill,
)
),
//child: CreateWallpaperLayouts().createWallpaper(visions),
),],
),
),
if(createWallpaper==true) const SizedBox(height:10),
if(createWallpaper==true) StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return OpacityAnimatedWidget.tween(
opacityEnabled: 1, //define start value
opacityDisabled: 0, //and end value
enabled: createWallpaper,
child: Row(
children: [
SizedBox(
width: 50.w,
child: OutlinedButton(
onPressed: () {
_saveWallpaper(wallpaperBytes);
setState(() {
saveWallpaperButtonText = "SAVED!";
});
Future.delayed(const Duration(milliseconds: 1300), () {
setState(() {
saveWallpaperButtonText = "SAVE";
});
});
//Navigator.pushReplacementNamed(context, '/masterclasses');
},
style: OutlinedButton.styleFrom(
primary: const Color(0xffE4BCB4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
side: const BorderSide(width: 3, color: Color(0xffE4BCB4)),
),
child: Text(
saveWallpaperButtonText,
style: const TextStyle(
color: Color(0xff393432),
fontSize: 14,
fontWeight: FontWeight.w700,
)
),
),
),
const SizedBox(width: 10),
],
),
);
}
),
if(createWallpaper==true) const SizedBox(height:50),
Row(
children: const [
Flexible(
child: Text("Goals & Affirmations",
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 21,
color: Color(0xff393432),
),
),
),
],
),
],
);
}
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Text("Add goals and affirmations.",
style: TextStyle(
fontSize: 15,
),),
],
),
const SizedBox(height: 10),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Column(
children: [
Card(
elevation: 0,
color: const Color(0xffEFEFEF),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: TextFormField(
key: _formKey,
controller: _goalsController,
maxLines: 8,
decoration: const InputDecoration(border: InputBorder.none),
),
)
),
const SizedBox(height: 10),
Row(
children: [
Container(
width: 50.w,
margin: const EdgeInsets.fromLTRB(0, 0, 0, 40),
child: OutlinedButton(
onPressed: () async{
setState(() {
saveGoalsButtonText = "SAVED!";
});
Future.delayed(const Duration(seconds: 1), () {
setState(() {
saveGoalsButtonText = "SAVE GOALS";
});
});
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
goals = _goalsController.text;
prefs.setString('goals', goals);
});
//Navigator.pushReplacementNamed(context, '/masterclasses');
},
style: OutlinedButton.styleFrom(
primary: const Color(0xffE4BCB4),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(18.0),
),
side: const BorderSide(width: 3, color: Color(0xffE4BCB4)),
),
child: Text(
saveGoalsButtonText,
style: const TextStyle(
color: Color(0xff393432),
fontSize: 14,
fontWeight: FontWeight.w700,
)
),
),
),
],
),
],
);
}
),
],
),
),
),
),
),
),
),
);
}
);
}
}

How can I give message when the text field is same as before?

When the name is already there
Without any change in the text field when clicking its showing
I was trying to update the name in firebase, it was working fine, but each time when I'm clicking edit without any change it's uploading to firebase. I don't want that to happen. Please help me out
Here is my code:
`import 'package:flutter/material.dart';
class EditProfile extends StatefulWidget {
#override
_EditProfileState createState() => _EditProfileState();
}
class _EditProfileState extends State<EditProfile> {
final TextEditingController nameController = TextEditingController();
final _keyChange = GlobalKey<FormState>();
bool btnTextChange = false;
TextEditingController _editingController = TextEditingController(text:"Johny Boy");
String initialText = "Johny Boy";
Widget _editTitleContainer() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(left: 20,top: 20,bottom: 20),
child: Text(
"Name",
),
),
Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
color: Colors.white,
),
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 20),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
child:
Form(
key: _keyChange,
child: TextField(
enableInteractiveSelection: true,
onSubmitted: (newValue){
setState(() {
initialText = newValue;
});
},
onChanged: (String? value) {
value!.isEmpty ? changeButtonColor(false) : changeButtonColor(true);
},
controller: _editingController,
decoration: InputDecoration(
border: InputBorder.none,
),)
)
),
],
);
}
#override
void dispose() {
_editingController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("sample"),
),
body: SafeArea(
child: Container(
child: Column(
children: [
_editTitleContainer(),
Container(
alignment: Alignment.center,
margin:EdgeInsets.only(top: 20),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
),
onPressed: () {
if (_keyChange.currentState!.validate()) {
_keyChange.currentState!.save();
successMessage();
}
},
child: Text(
"EDIT",
style: TextStyle(
color: Color(0xFF527DAA),
letterSpacing: 1.5,
fontSize: 15,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
),
),
),
),
],
),
),
),
);
}
void successMessage() {
String name = _editingController.text.trim();
if (name.isNotEmpty) {
setState(() {
showDialog(
context: context,
builder: (ctx) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
title: Text("Name Changed Success"),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(ctx).pop();
},
),
],
);
},
);
});
}else {
setState(() {
showDialog(
context: context,
builder: (ctx) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)),
title: Text("Error!"),
content: Text("Enter Your Name"),
actions: [
TextButton(
child: Text("Close"),
onPressed: () {
Navigator.of(ctx).pop();
},
),
],
);
},
);
});
}
}
}`.
You only need to compare the initial text and the text of _editingController. If they are not the same, then you can update and show successMessage. It will look like this:
ElevatedButton(
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 20),
),
onPressed: () {
if (_keyChange.currentState!.validate()) {
// HERE!
if (initialText != _editingController.text) {
_keyChange.currentState!.save();
successMessage();
}
}
},

Flutter - how to add rows with a click on a button

I want the 6 ball row(plz refer to this image) to be added when I click the '+Add Rows' button, but I've got 1 problem which is that I'm not sure that it has a Listview like I coded.
Please help me to complete 'void addRow()' to add a row with a click on a button.
And could you give me some tips on how to get a new row with completely different random numbers from other rows?
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'dart:math';
import 'package:barcode_scan/barcode_scan.dart';
void main() => runApp(
MaterialApp(
home: BallPage()
),
);
class BallPage extends StatefulWidget {
#override
_BallPageState createState() => _BallPageState();
}
class _BallPageState extends State<BallPage>{
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
drawer: new Drawer(),
appBar: AppBar(
title: Text(
'Magic 6 balls'),
backgroundColor: Colors.black,
actions: <Widget>[
new IconButton(
icon: new Icon(MdiIcons.squareInc),
color: Colors.white,
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => SecondRoute())
);
},
),
],
),
body: Number(),
);
}
}
class SecondRoute extends StatefulWidget {
#override
_SecondRouteState createState() {
return new _SecondRouteState();
}
}
class _SecondRouteState extends State<SecondRoute>{
String result ="Hey there!";
Future _scanQR() async {
try{
String qrResult = await BarcodeScanner.scan();
setState(() {
result = qrResult;
});
} on PlatformException catch (ex) {
if (ex.code == BarcodeScanner.CameraAccessDenied){
setState(() {
result = "Camera permission was denied";
});
} else {
setState(() {
result = "Unknown Error $ex";
});
}
} on FormatException {
setState(() {
result = "You pressed the black button before scanning anything";
});
}catch (ex) {
setState(() {
result = "Unknown Error $ex";
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('QR Code Scan'),
),
body: Center(
child: Text(
result,
style: new TextStyle(fontSize: 20.0),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: _scanQR,
label: Text('Scan'),
icon: Icon(Icons.camera_alt),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
class Number extends StatefulWidget {
#override
_NumberState createState() => _NumberState();
}
class _NumberState extends State<Number> {
int ball1 = 1;
int ball2 = 1;
int ball3 = 1;
int ball4 = 1;
int ball5 = 1;
int ball6 = 1;
void randomNumbers() {
setState(() {
ball1 = Random().nextInt(49) + 1;
ball2 = Random().nextInt(49) + 1;
ball3 = Random().nextInt(49) + 1;
ball4 = Random().nextInt(49) + 1;
ball5 = Random().nextInt(49) + 1;
ball6 = Random().nextInt(49) + 1;
});
}
void addRows(){
setState(() {
});
}
void removeRows(){
setState(() {
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: ListView(
children: <Widget>[
SizedBox(height: 100.0),
Center(
child: Text('Winners Number')
),
SizedBox(height: 16.0),
buildForm(),
SizedBox(height: 16.0),
RaisedButton.icon(
icon: Icon(Icons.add),
label: Text('Add Rows'),
onPressed: () {
addRows();
},
),
],
),
),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
randomNumbers();
},
label: Text(
'Click Here!'),
icon: Icon(
Icons.loop),
backgroundColor: Colors.black,
),
);
}
Widget buildForm() {
List<Widget> list = new List();
for (var index = 0; index < 1; index++) {
list.add(Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 60,
width: 60,
child: Center
(
child: Text(
'$ball1',
style: TextStyle(
fontSize: 20.0,
),
),
),
decoration: BoxDecoration(
color: Colors.yellow,
shape: BoxShape.circle,
),
),
Container(
height: 60,
width: 60,
child: Center
(
child: Text(
'$ball2',
style: TextStyle(
fontSize: 20.0,
),
),
),
decoration: BoxDecoration(
color: Colors.yellow,
shape: BoxShape.circle,
),
),
Container(
height: 60,
width: 60,
child: Center
(
child: Text(
'$ball3',
style: TextStyle(
fontSize: 20.0,
),
),
),
decoration: BoxDecoration(
color: Colors.yellow,
shape: BoxShape.circle,
),
),
Container(
height: 60,
width: 60,
child: Center
(
child: Text(
'$ball4',
style: TextStyle(
fontSize: 20.0,
),
),
),
decoration: BoxDecoration(
color: Colors.yellow,
shape: BoxShape.circle,
),
),
Container(
height: 60,
width: 60,
child: Center
(
child: Text(
'$ball5',
style: TextStyle(
fontSize: 20.0,
),
),
),
decoration: BoxDecoration(
color: Colors.yellow,
shape: BoxShape.circle,
),
),
Container(
height: 60,
width: 60,
child: Center
(
child: Text(
'$ball6',
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
),
decoration: BoxDecoration(
color: Colors.black,
shape: BoxShape.circle,
),
),
],
));
list.add(
SizedBox(
height: 12.0,
));
}
return Column(
children: list);
}
}
What I would recommend to do is, have the rows always there but just hide them with Visibility widget.
Add an int counter variable and increment it on each click on addRow.
Then wrap your ball widgets around with visibility and do something like that:
Pseudo-code
Visibilty(
visible: counter == 1,
child: BallWidget(),
)
... and so on for all the other ball widgets.
Hope it helps.