setState() on showDialog() from initState() is not changing the state. Flutter - 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.

Related

How to animate a container on click in flutter

I am new to flutter animation, I have a stopwatch screen with a container that contains the stopwatch, a container with a list of laps, and 3 floating action buttons that do three things, reset, play-pause and lap. I want the stopwatch container to animate up when clicking on the lap button and then animate down when clicking on the reset button.
class _StopWatchScreenState extends State<StopWatchScreen>
with SingleTickerProviderStateMixin {
final StopWatchTimer _stopWatchTimer = StopWatchTimer();
final _isHours = true;
late AnimationController controller;
bool isPlaying = false;
bool lapClicked = false;
double value = 150.0;
final ScrollController scrollController = ScrollController();
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 200));
}
void dispose() {
super.dispose();
_stopWatchTimer.dispose();
scrollController.dispose();
controller.dispose();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
Center(
child: Padding(
padding: EdgeInsets.only(top: value), // Issue here
child: AnimatedContainer(
child: Center(
child: StreamBuilder<int>(
stream: _stopWatchTimer.rawTime,
initialData: _stopWatchTimer.rawTime.value,
builder: (context, snapshot) {
final value = snapshot.data;
final displayTime = StopWatchTimer.getDisplayTime(
value!,
hours: _isHours);
return Text(
displayTime,
style: GoogleFonts.lato(
fontSize: 40.0, color: Colors.white),
);
})),
width: 350.0,
height: 450.0,
decoration: BoxDecoration(
border: Border.all(color: Colors.white, width: 5.0),
shape: BoxShape.circle),
duration: const Duration(milliseconds: 100),
curve: Curves.fastLinearToSlowEaseIn,
),
),
),
Visibility(
visible: lapClicked,
child: Container(
height: 280.0,
child: StreamBuilder<List<StopWatchRecord>>(
stream: _stopWatchTimer.records,
initialData: _stopWatchTimer.records.value,
builder: (context, snapshot) {
final value = snapshot.data;
if (value!.isEmpty) {
return Container();
}
Future.delayed(const Duration(milliseconds: 100), () {
scrollController.animateTo(
scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 200),
curve: Curves.easeOut);
});
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: value.length,
itemBuilder: (context, index) {
final data = value[index];
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: Text(
'Lap ${index + 1}',
style: GoogleFonts.lato(
fontSize: 30.0, color: Colors.white70),
),
),
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: Text('${data.displayTime}',
style: GoogleFonts.lato(
fontSize: 30.0,
color: Colors.white70)),
)
],
),
const Padding(
padding: EdgeInsets.only(top: 5.0),
child: Opacity(
opacity: 0.1,
child: Divider(
thickness: 1.5,
color: Colors.white70,
),
),
)
],
);
},
controller: scrollController,
);
},
),
),
),
],
),
floatingActionButton: Padding(
padding: const EdgeInsets.only(left: 30.0, bottom: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FloatingActionButton(
onPressed: () {
setState(() {
lapClicked = false;
value = 190.0;
});
controller.reverse();
_stopWatchTimer.onExecute.add(StopWatchExecute.reset);
},
child: const Icon(
Icons.refresh,
size: 30.0,
),
),
FloatingActionButton(
onPressed: () {
toggleIcon();
if (isPlaying == true) {
_stopWatchTimer.onExecute.add(StopWatchExecute.start);
} else {
_stopWatchTimer.onExecute.add(StopWatchExecute.stop);
}
},
child: AnimatedIcon(
icon: AnimatedIcons.play_pause,
size: 35.0,
progress: controller,
),
),
FloatingActionButton(
onPressed: () {
setState(() {
lapClicked = true;
value = 10.0;
});
_stopWatchTimer.onExecute.add(StopWatchExecute.lap);
},
child: const Icon(
Icons.timer,
size: 30.0,
),
),
],
),
),
),
);
}
void toggleIcon() {
setState(() {
isPlaying = !isPlaying;
isPlaying ? controller.forward() : controller.reverse();
});
}
}
Use Animated Container with visibility
see this for animated container
Visibility(
visible:true,//controll to click on your lap button
child: AnimatedContainer(),
)
Animated Container
I used AnimatedContainer to animate the stopwatch and fixed the animation issue by removing the padding property from the container and replacing it with a margin property

How can I make the on pressed function lead to a webpage?

I have this bit of code and I want the onPressed function for all options on my menu to open a url. I'm not entirely familar with this so I need a little help.
Here is my code below
class NewProfile extends StatefulWidget {
const NewProfile({Key key, this.scaffoldKey}) : super(key: key);
final GlobalKey<ScaffoldState> scaffoldKey;
_NewProfileState createState() => _NewProfileState();
}
class _NewProfileState extends State<NewProfile> {
Widget _menuHeader() {
final state = context.watch<AuthState>();
if (state.userModel == null) {
return ConstrainedBox(
constraints: BoxConstraints(minWidth: 200, minHeight: 100),
child: Center(
child: Text(
'Login to continue',
style: TextStyles.onPrimaryTitleText,
),
),
).ripple(() {
_logOut();
// Navigator.of(context).pushNamed('/signIn');
});
} else {
return Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 120,
width: 120,
margin: EdgeInsets.only(left: 17, top: 10),
decoration: BoxDecoration(
border: Border.all(color: kPrimaryColor, width: 2),
borderRadius: BorderRadius.circular(200),
image: DecorationImage(
image: customAdvanceNetworkImage(
state.userModel.profilePic ?? Constants.dummyProfilePic,
),
fit: BoxFit.cover,
)),
),
SizedBox(
height: 20,
),
ListTile(
onTap: () {
Navigator.push(context,
ProfilePage.getRoute(profileId: state.userModel.userId));
},
title: Row(
children: <Widget>[
UrlText(
text: state.userModel.displayName ?? "",
style: TextStyles.onPrimaryTitleText
.copyWith(color: Colors.black, fontSize: 20),
),
SizedBox(
width: 3,
),
state.userModel.isVerified ?? false
? customIcon(context,
icon: AppIcon.blueTick,
istwitterIcon: true,
iconColor: AppColor.primary,
size: 18,
paddingIcon: 3)
: SizedBox(
width: 0,
),
],
),
subtitle: customText(
state.userModel.userName,
style: TextStyles.onPrimarySubTitleText
.copyWith(color: Colors.black54, fontSize: 15),
),
trailing: customIcon(context,
icon: AppIcon.arrowDown,
iconColor: AppColor.primary,
paddingIcon: 20),
),
Container(
alignment: Alignment.center,
child: Row(
children: <Widget>[
SizedBox(
width: 17,
),
_tappbleText(context, '${state.userModel.getFollower}',
' Connections', 'FollowerListPage'),
SizedBox(width: 10),
_tappbleText(context, '${state.userModel.getFollowing}',
' Mentors', 'FollowingListPage'),
],
),
),
],
),
);
}
}
Widget _tappbleText(
BuildContext context, String count, String text, String navigateTo) {
return InkWell(
onTap: () {
var authstate = context.read<AuthState>();
List<String> usersList;
authstate.getProfileUser();
Navigator.pop(context);
switch (navigateTo) {
case "FollowerListPage":
usersList = authstate.userModel.followersList;
break;
case "FollowingListPage":
usersList = authstate.userModel.followingList;
break;
default:
}
Navigator.push(
context,
FollowerListPage.getRoute(
profile: authstate.userModel, userList: usersList));
},
child: Row(
children: <Widget>[
customText(
'$count ',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 17),
),
customText(
'$text',
style: TextStyle(color: AppColor.darkGrey, fontSize: 17),
),
],
),
);
}
ListTile _menuListRowButton(String title,
{Function onPressed, IconData icon, bool isEnable = false}) {
return ListTile(
onTap: () {
if (onPressed != null) {
onPressed();
}
},
leading: icon == null
? null
: Padding(
padding: EdgeInsets.only(top: 5),
child: customIcon(
context,
icon: icon,
size: 25,
iconColor: isEnable ? AppColor.darkGrey : AppColor.lightGrey,
),
),
title: customText(
title,
style: TextStyle(
fontSize: 20,
color: isEnable ? AppColor.secondary : AppColor.lightGrey,
),
),
);
}
Positioned _footer() {
return Positioned(
bottom: 0,
right: 0,
left: 0,
child: Column(
children: <Widget>[
Divider(height: 0),
Row(
children: <Widget>[
TextButton(
onPressed: () {
Navigator.push(
context,
ScanScreen.getRoute(
context.read<AuthState>().profileUserModel));
},
child: Image.asset(
"assets/images/qr.png",
height: 25,
),
),
],
),
],
),
);
}
void _logOut() {
final state = Provider.of<AuthState>(context, listen: false);
Navigator.pop(context);
state.logoutCallback();
}
// ignore: unused_element
void _navigateTo(String path) {
Navigator.pop(context);
Navigator.of(context).pushNamed('/$path');
}
#override
Widget build(BuildContext context) {
return Center(
child: SafeArea(
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(bottom: 45),
child: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
Container(
child: _menuHeader(),
),
Divider(),
_menuListRowButton('Profile',
icon: AppIcon.profiles, isEnable: true, onPressed: () {
var state = context.read<AuthState>();
Navigator.push(
context, ProfilePage.getRoute(profileId: state.userId));
}),
_menuListRowButton('Help Center',
icon: AppIcon.helped, isEnable: true, onPressed: () {
var state = context.read<AuthState>();
Navigator.push(
context, ProfilePage.getRoute(profileId: state.userId));
}),
_menuListRowButton('Terms of Service',
icon: AppIcon.agreement, isEnable: true, onPressed: () {
var state = context.read<AuthState>();
Navigator.push(
context, ProfilePage.getRoute(profileId: state.userId));
}),
_menuListRowButton('Privacy Policy',
icon: AppIcon.privacy, isEnable: true, onPressed: () {
var state = context.read<AuthState>();
Navigator.push(
context, ProfilePage.getRoute(profileId: state.userId));
}),
_menuListRowButton('Cookie Use',
icon: AppIcon.cookies, isEnable: true, onPressed: () {
var state = context.read<AuthState>();
Navigator.push(
context, ProfilePage.getRoute(profileId: state.userId));
}),
Divider(),
_menuListRowButton('Logout',
icon: AppIcon.logout, onPressed: _logOut, isEnable: true),
],
),
),
_footer()
],
),
),
);
}
}
I want them to open to different urls on the web. If there is anything I should add such as dependencies or import any packages, please let me know.
You can navigate to a webpage with the Url Launcher package.
Future<void> launchURL(String url) async {
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}

Flutter table_calendar load today

Im using table_calendar package in my project, but ive faced two problems so far :
The calendar doesnt load todays events below the calendar, i would love to hear some ideas how to get this one done.
Even if i put (code below) in tables parameters, it doesnt allow to switch calendar modes.
code for swiching calendar modes for 2nd bullet point of my problems:
availableCalendarFormats: const {
CalendarFormat.month: '',
CalendarFormat.week: '',
},
Just in case, here is the whole code for page which has problems :
class Lecture_graph extends StatefulWidget {
Lecture_graph({Key key}) : super(key: key);
#override
State<Lecture_graph> createState() => myLectureGraph();
}
class myLectureGraph extends State<Lecture_graph>
with TickerProviderStateMixin {
List _selectedEvents;
DateTime _selectedDate = DateTime.now();
Map<DateTime, List<Lecture>> _events;
CalendarController _calendarController;
AnimationController _animationController;
List<Lecture> _lectures;
String coursecode = "";
bool isJoin, isBreaks = false;
bool isLoading = true;
final Map<DateTime, List> _holidays = {
// DateTime(2021, 1, 1): ['New Year\'s Day'],
// DateTime(2021, 2, 14): ['Valentine\'s Day'],
// DateTime(2021, 3, 8): ['Woman\'s Day'],
};
Future<Map<DateTime, List>> getLectures(DateTime _selectedDate) async {
print("getLectures started.");
setState(() {
isLoading = true;
});
Map<DateTime, List<Lecture>> mapFetch = {};
//get saved course
if (coursecode == "" || coursecode == null) {
coursecode = await _checkSavedCourse();
//debug
print('courscode recieved from sharedprefs');
}
//build request URL
var requestURL =
'https://lekcijas.va.lv/lekcijas_android/getMonthLectures.php?date=' +
DateFormat('yyyy-MM').format(_selectedDate) +
(isBreaks ? "&breaks" : "") +
(isJoin ? "&join" : "") +
"&program=" +
coursecode +
"&lang=" +
AppLocalizations.of(context).translate('request_language');
print("Lecture request url : $requestURL");
//wait for response
var response = await http.get(Uri.parse(requestURL));
var data = json.decode(response.body)["result"];
//clear array after each request
if (_lectures != null) _lectures.clear();
try {
//create lectures from json response
_lectures = List<Lecture>.from(data.map((x) => Lecture.fromJson(x)));
} on Exception catch (_) {
print("Error occured getting lectures");
}
_lectures.forEach((element) {
if (mapFetch[element.lecture_date] != null) {
mapFetch[element.lecture_date] += [element];
} else {
mapFetch[element.lecture_date] = [element];
}
});
setState(() {
isLoading = false;
});
print("getLectures finished.");
return mapFetch;
}
Future<void> _saveVales(String key, bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
print("Sharedpref $key is set to $value now");
prefs.setBool(key, value);
}
Future<void> _checkSavedParameters() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
isBreaks = prefs.getBool('lectures_breaks') == null
? false
: prefs.getBool('lectures_breaks');
isJoin = prefs.getBool('lectures_join') == null
? false
: prefs.getBool('lectures_join');
}
Future<String> _checkSavedCourse() async {
//check saved parameters for lecture requests too
await _checkSavedParameters();
SharedPreferences prefs = await SharedPreferences.getInstance();
String _coursecode = prefs.getString('savedCourse');
if (_coursecode == "" || _coursecode == null) {
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(builder: (context) => CourseSelectionPage()),
);
return null;
} else {
return _coursecode;
}
}
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
setState(() {
_selectedEvents = events;
});
}
#override
void initState() {
super.initState();
//enable portrait only mode
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
_selectedEvents = [];
_calendarController = CalendarController();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_animationController.forward();
WidgetsBinding.instance.addPostFrameCallback((_) {
getLectures(_selectedDate).then((val) => setState(() {
_events = val;
}));
});
}
#override
void dispose() {
_calendarController.dispose();
//unlock orientation mode
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(coursecode +
" | " +
AppLocalizations.of(context).translate('lectures_title')),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.settings,
color: Colors.white,
),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text(
AppLocalizations.of(context).translate('settings')),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
CupertinoSwitch(
value: isJoin,
onChanged: (bool value) {
_saveVales('lectures_join', value);
isJoin = value;
WidgetsBinding.instance
.addPostFrameCallback((_) {
getLectures(_selectedDate)
.then((val) => setState(() {
_events = val;
}));
});
},
),
Text(AppLocalizations.of(context)
.translate('join_lectures'))
],
),
SizedBox(height: 10),
Row(
children: [
CupertinoSwitch(
value: isBreaks,
onChanged: (bool value) {
_saveVales('lectures_breaks', value);
isBreaks = value;
WidgetsBinding.instance
.addPostFrameCallback((_) {
getLectures(_selectedDate)
.then((val) => setState(() {
_events = val;
}));
});
},
),
Text(AppLocalizations.of(context)
.translate('show_breaks'))
],
),
SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: OutlinedButton(
onPressed: () {
//close popup
Navigator.pop(context);
//close page
Navigator.pop(context);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CourseSelectionPage()),
);
},
child: Text(
AppLocalizations.of(context)
.translate('select_course'),
style: TextStyle(color: Colors.lime),
)),
)
],
),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text(AppLocalizations.of(context)
.translate('close')),
),
],
);
},
);
},
);
},
)
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
isLoading
? Expanded(child: Center(child: CircularProgressIndicator()))
: _buildTableCalendarWithBuilders(),
const SizedBox(height: 2.0),
Expanded(child: _buildEventList()),
],
),
),
);
}
Widget _buildTableCalendarWithBuilders() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
color: Colors.white,
margin: const EdgeInsets.all(8.0),
clipBehavior: Clip.antiAlias,
child: TableCalendar(
locale:
AppLocalizations.of(context).translate('request_language') ==
'lv'
? "lv_LV"
: "en_US",
initialSelectedDay: _selectedDate,
calendarController: _calendarController,
events: _events,
holidays: _holidays,
initialCalendarFormat: CalendarFormat.month,
formatAnimation: FormatAnimation.scale,
startingDayOfWeek: StartingDayOfWeek.monday,
availableGestures: AvailableGestures.all,
availableCalendarFormats: const {
CalendarFormat.month: '',
CalendarFormat.week: '',
},
calendarStyle: CalendarStyle(
outsideDaysVisible: false,
weekendStyle: TextStyle().copyWith(color: Colors.blue[800]),
holidayStyle: TextStyle().copyWith(color: Colors.blue[800]),
),
daysOfWeekStyle: DaysOfWeekStyle(
weekendStyle: TextStyle().copyWith(color: Colors.blue[600]),
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonVisible: false,
),
builders: CalendarBuilders(
selectedDayBuilder: (context, date, _) {
return FadeTransition(
opacity:
Tween(begin: 0.0, end: 1.0).animate(_animationController),
child: Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 5.0, left: 6.0),
color: Colors.deepOrange[300],
width: 100,
height: 100,
child: Text(
'${date.day}',
style: TextStyle().copyWith(fontSize: 16.0),
),
),
);
},
todayDayBuilder: (context, date, _) {
return Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 5.0, left: 6.0),
color: Colors.amber[400],
width: 100,
height: 100,
child: Text(
'${date.day}',
style: TextStyle().copyWith(fontSize: 16.0),
),
);
},
markersBuilder: (context, date, events, holidays) {
final children = <Widget>[];
if (events.isNotEmpty) {
children.add(
Positioned(
right: 1,
bottom: 1,
child: _buildEventsMarker(date, events),
),
);
}
if (holidays.isNotEmpty) {
children.add(
Positioned(
right: -2,
top: -2,
child: _buildHolidaysMarker(),
),
);
}
return children;
},
),
onDaySelected: (date, events, holidays) {
_onDaySelected(date, events);
_animationController.forward(from: 0.0);
},
onVisibleDaysChanged: _onVisibleDaysChanged,
),
),
],
);
}
void _onVisibleDaysChanged(
DateTime first, DateTime last, CalendarFormat format) {
_selectedDate = first;
WidgetsBinding.instance.addPostFrameCallback((_) {
getLectures(_selectedDate).then((val) => setState(() {
_events = val;
}));
});
print('CALLBACK: _onVisibleDaysChanged');
}
Widget _buildEventsMarker(DateTime date, List events) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _calendarController.isSelected(date)
? Colors.brown[500]
: _calendarController.isToday(date)
? Colors.brown[300]
: Colors.green[400],
),
width: 18.0,
height: 18.0,
child: Center(
child: Text(
'${events.length}',
style: TextStyle().copyWith(
color: Colors.white, fontSize: 12.0, fontWeight: FontWeight.w900),
),
),
);
}
Widget _buildHolidaysMarker() {
return Icon(
Icons.add_box,
size: 20.0,
color: Colors.blueGrey[800],
);
}
Widget _buildEventList() {
return ListView(
children: _selectedEvents.reversed
.map((lecture) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.1),
// borderRadius: BorderRadius.circular(2.0),
color: hexToColor(lecture.color),
),
margin:
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 1.5),
child: ListTile(
title: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
lecture.start + " - " + lecture.end,
style: new TextStyle(
fontSize: 12.0,
color: Colors.black,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: Text(lecture.lecture,
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
)),
),
],
),
onTap: () => displayDialog(lecture, context),
),
))
.toList(),
);
}
void displayDialog(Lecture selectedLecture, BuildContext ctx) {
//if selected lecture is a break
if (!selectedLecture.lecturer.isEmpty &&
!selectedLecture.classroom.isEmpty &&
!selectedLecture.programs.isEmpty) {
showDialog(
barrierDismissible: true,
context: ctx,
builder: (BuildContext context) => new AlertDialog(
title: new Text(AppLocalizations.of(context).translate('info_title')),
content: new Wrap(
runSpacing: 5,
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_time') +
selectedLecture.start +
" - " +
selectedLecture.end),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_lecturer') +
selectedLecture.lecturer),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_classroom') +
selectedLecture.classroom),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_lecture') +
selectedLecture.lecture),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_date') +
DateFormat('yyyy-MM-dd')
.format(selectedLecture.lecture_date)
.toString()),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
AppLocalizations.of(context).translate('info_programs') +
selectedLecture.programs),
),
],
),
actions: [
new TextButton(
child: Text(AppLocalizations.of(context).translate('close')),
onPressed: () => Navigator.pop(context, true),
),
],
),
);
}
}
}
In case someone wants to see JSON request results, here is the link for that.
So i got this fixed, adding this to TableCalendar() parameters:
(i called selectedEvents variable update once calendar finished building (because im showing CircularProgressIndicator instead of it while i recieve data from http request) )
onCalendarCreated: (d1, d2, cf){WidgetsBinding.instance
.addPostFrameCallback((_) => _onDaySelected(_selectedDate, _events[_selectedDate]));},
changed _onDaySelected method to:
(here i change selectedday variable to day recieved from calendar click and change state of selectedEvents, replacing them with total_events_map[key_which_is_selectedDay])
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
//dates are used with nulled time
_selectedDate = DateTime(day.year, day.month, day.day, 0, 0, 0);
setState(() {
_selectedEvents = _events[_selectedDate];
});
}
and changed _buildEventList() to this :
(so if selectedEvents are empty, it tells user so, if not, generates a list of items from selectedEvents)
Widget _buildEventList() {
if(_selectedEvents == null)
return ListView(
children: [
Card(
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.all(8.0),
child: ListTile(
title: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(tr('nothing_planned'),
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
)),
),
],
),
),
),
],
);
else return ListView(
children: _selectedEvents.reversed
.map((lecture) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.1),
// borderRadius: BorderRadius.circular(2.0),
color: hexToColor(lecture.color),
),
margin:
const EdgeInsets.symmetric(horizontal: 6.0, vertical: 1.5),
child: ListTile(
title: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
lecture.start + " - " + lecture.end,
style: new TextStyle(
fontSize: 12.0,
color: Colors.black,
),
),
),
Align(
alignment: Alignment.centerLeft,
child: Text(lecture.lecture,
style: new TextStyle(
fontSize: 16.0,
color: Colors.black,
)),
),
],
),
onTap: () => displayDialog(lecture, context),
),
))
.toList(),
);
}

setState() not working properly in 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
}

Resetting Radio List in Flutter

I am still a novice with flutter and I am working on a quiz app right now
In the radio button list whenever the app goes to next question the radio buttons are not getting reset and I will be grateful if someone can guide me on how I can reset radio button on calling next question function
Pseudocode
class _QuizPageState extends State<QuizPage> {
List<dynamic> myQuestion;
_QuizPageState(this.myQuestion);
int i = 0;
int count = 0;
int selectedRadioTile;
int marks = 0;
var selected;
Widget choiceButton(String k, int value) {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 10,
),
child: RadioListTile(
value: value,
groupValue: selectedRadioTile,
title: Container(
child: Text(myQuestion[i][k] ?? "None"),
),
onChanged: (val) {
setSelectedRadioTile(val);
selected = val;
},
activeColor: Colors.green,
selected: true,
),
);
}
void initState() {
selectedRadioTile = 0;
super.initState();
}
setSelectedRadioTile(int val) {
setState(() {
selectedRadioTile = val;
});
}
void checkAnswer() {
var e = int.parse(myQuestion[i]["Answer"]);
if (e == selected) {
marks = marks + 1;
} else {
print("wrong");
}
nextquestion();
}
void nextquestion() {
setState(() {
if (count < 9) {
i = randomBetween(0, myQuestion.length);
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(marks: marks),
));
}
});
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Alert",
),
content: Text("You Can't Go Back At This Stage."),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Ok',
),
)
],
));
},
child: Scaffold(
appBar: AppBar(
elevation: 30.0,
title: Center(
child: Text(
'Quiz',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontFamily: "Quando",
fontWeight: FontWeight.bold,
),
),
),
backgroundColor: Colors.amber[800],
),
body: LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Center(
child: Container(
padding: EdgeInsets.only(top: 20, left: 10),
child: Text(
myQuestion[i]["Question"] ?? "None",
style: TextStyle(
fontSize: 15.0,
fontFamily: "Quando",
fontWeight: FontWeight.bold,
),
),
),
),
SizedBox(
height: 20,
),
Expanded(
child: AspectRatio(
aspectRatio: 16 / 11,
child: ClipRect(
child: SizedBox(
height: 50,
child: PhotoView(
imageProvider: AssetImage(
myQuestion[i]["Image"] ?? "None"),
minScale:
PhotoViewComputedScale.contained *
0.5,
maxScale:
PhotoViewComputedScale.covered * 2,
initialScale: 0.6,
backgroundDecoration: BoxDecoration(
color: Theme.of(context).canvasColor,
),
),
),
),
),
),
Text(
"To adjust the image double Tap",
style: TextStyle(
fontFamily: "Quando",
color: Colors.black26,
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
],
),
),
SizedBox(
height: 10,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
choiceButton("option1", 1),
choiceButton("option2", 2),
choiceButton("option3", 3),
choiceButton("option4", 4),
],
),
),
Expanded(
flex: 0,
child: RaisedButton(
splashColor: Colors.blueAccent,
color: Colors.blueAccent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
onPressed: () {
checkAnswer();
count = count + 1;
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Explaination",
),
content: Text(
myQuestion[i]["Explanation"] ?? "None",
style: TextStyle(
fontSize: 15.0,
fontFamily: "Quando",
),
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Ok',
),
)
],
));
},
child: Text(
'Submit',
),
),
),
SizedBox(
height: 40,
)
],
),
),
),
);
},
),
),
);
}
}
You could just set selectedRadioTile to 0 in nextQuestion:
void nextquestion() {
setState(() {
selectedRadioTile = 0;
if (count < 9) {
i = randomBetween(0, myQuestion.length);
} else {
Navigator.of(context).pushReplacement(MaterialPageRoute(
builder: (context) => resultpage(marks: marks),
));
}
});
}