Im developing a soccer match schedule application .
I want to add a countdown when kick off the match.
How to best practice make a countdown widget with the format hh : mm : ss ?
Both in the comment will have good results. It is also best to rely on Flutter documentation for guidance.
With that, I've made a little sample of a countdown timer based on your requirements.
First, I've tried to define what kind of input I'm going to use. Decided to implement the input this way:
//Update the time in 'YYYY-MM-DD HH:MM:SS' format
final eventTime = DateTime.parse('2021-01-09 03:41:00');
So that I can supply the exact date and time I needed.
Then get the difference from the current date and time and convert it to seconds:
int timeDiff = eventTime.difference(DateTime.now()).inSeconds;
Then created a function that would handle the clocking of the timer:
void handleTick() {
if (timeDiff > 0) {
if (isActive) {
setState(() {
if (eventTime != DateTime.now()) {
timeDiff = timeDiff - 1;
} else {
print('Times up!');
//Do something
}
});
}
}
}
So when the timer is working as expected, I've just used mathematical operation to define the remaining days, hours, minutes and seconds:
int days = timeDiff ~/ (24 * 60 * 60) % 24;
int hours = timeDiff ~/ (60 * 60) % 24;
int minutes = (timeDiff ~/ 60) % 60;
int seconds = timeDiff % 60;
If you just need the HH:MM:SS format you can just play around and omit that section, check the working code:
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(TimerApp());
class TimerApp extends StatefulWidget {
#override
_TimerAppState createState() => _TimerAppState();
}
//Update the time in 'YYYY-MM-DD HH:MM:SS' format
final eventTime = DateTime.parse('2021-01-09 03:41:00');
class _TimerAppState extends State<TimerApp> {
static const duration = const Duration(seconds: 1);
int timeDiff = eventTime.difference(DateTime.now()).inSeconds;
bool isActive = false;
Timer timer;
void handleTick() {
if (timeDiff > 0) {
if (isActive) {
setState(() {
if (eventTime != DateTime.now()) {
timeDiff = timeDiff - 1;
} else {
print('Times up!');
//Do something
}
});
}
}
}
#override
Widget build(BuildContext context) {
if (timer == null) {
timer = Timer.periodic(duration, (Timer t) {
handleTick();
});
}
int days = timeDiff ~/ (24 * 60 * 60) % 24;
int hours = timeDiff ~/ (60 * 60) % 24;
int minutes = (timeDiff ~/ 60) % 60;
int seconds = timeDiff % 60;
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.grey[700],
title: Center(
child: Text('Countdown Timer'),
),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
LabelText(
label: 'DAYS', value: days.toString().padLeft(2, '0')),
LabelText(
label: 'HRS', value: hours.toString().padLeft(2, '0')),
LabelText(
label: 'MIN', value: minutes.toString().padLeft(2, '0')),
LabelText(
label: 'SEC', value: seconds.toString().padLeft(2, '0')),
],
),
SizedBox(height: 60),
Container(
width: 200,
height: 47,
margin: EdgeInsets.only(top: 30),
child: RaisedButton(
color: isActive ? Colors.grey : Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25)),
child: Text(isActive ? 'STOP' : 'START'),
onPressed: () {
setState(() {
isActive = !isActive;
});
},
),
)
],
),
),
),
);
}
}
class LabelText extends StatelessWidget {
LabelText({this.label, this.value});
final String label;
final String value;
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 5),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
color: Colors.grey,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'$value',
style: TextStyle(
color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
),
Text(
'$label',
style: TextStyle(
color: Colors.white70,
),
),
],
),
);
}
}
Here is the output of the countdown timer I've created:
Related
Currently I am building a chat App and my goal is to display the "time/date" over the messages. However, since this gets very messy I only want to show the date once over every hour (similiary to Facebook Messenger)pic of current chat screen. Since I am using Firebase, I store every chat with a collection 'messages' that contain a document for every message in that chat. The document contains String:'messageType', String: 'messageContent', String: 'authorUUID' and timestamp timestamp.
I thought about building a Map that combines timestamp and Content, but since I am a beginner I am not sure if this approach is right. Thank you very much!
As of now my code looks the following:
import 'package:flutter/material.dart';
import 'package:native_now/app_constants/app_colors.dart';
import 'package:native_now/models/chat_message_model.dart';
class ChatMessageTile extends StatelessWidget {
final ChatMessageModel chatMessageModel;
const ChatMessageTile({Key key, this.chatMessageModel}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.only(left: 14, right: 14, top: 10, bottom: 10),
child: Column(
children: [ chatMessageModel.timestamp.toDate().toLocal().hour != DateTime.now().hour ?
Text(chatMessageModel.getRelevantTime(),
style: Theme.of(context)
.textTheme
.bodyText2
.copyWith(color: AppColors.grey,fontSize: 12)) : Container(),
SizedBox(height: 4,),
Align(
alignment: (chatMessageModel.userIsSender()
? Alignment.topRight
: Alignment.topLeft),
child: Stack(alignment: Alignment.center,
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
color: (chatMessageModel.userIsSender()
? AppColors.pureBlue
: AppColors.onyx),
),
padding:
EdgeInsets.only(left: 12, right: 12, bottom: 12, top: 12),
child: Container(
child: Text(
chatMessageModel.messageContent,
style: Theme.of(context)
.textTheme
.bodyText1
.copyWith(color: AppColors.white),textAlign: (chatMessageModel.userIsSender()
? TextAlign.right
: TextAlign.left),
),
),
),
/*Positioned(
right: 2,
bottom: 2,
child: Text(chatMessageModel.getRelevantTime(),
style: Theme.of(context)
.textTheme
.bodyText2
.copyWith(color: AppColors.onyx,fontSize: 12))), */
],
)),
],
),
);
}
}
class ChatMessageModel {
final String messageContent;
final String messageType;
final Timestamp timestamp;
final String authorUUID;
final DocumentReference documentReference;
final bool messageRead;
final bool isLiked;
ChatMessageModel(this.messageContent, this.messageType,
this.documentReference, this.timestamp, this.authorUUID, this.messageRead,
this.isLiked);
ChatMessageModel.fromDocumentSnapshot(DocumentSnapshot documentSnapshot)
: messageContent = documentSnapshot.get("messageContent"),
messageType = documentSnapshot.get("messageType"),
timestamp = documentSnapshot.get("timestamp"),
authorUUID = documentSnapshot.get("authorUUID"),
documentReference = documentSnapshot.reference,
messageRead = false,
isLiked = false;
final List<ChatMessageModel> recentMessages;
List<Map<String, Object>> get groupedTimeBlocks {
return List.generate(messageContent.length, (index) {
final hour = DateTime.now().subtract(Duration(hours: index));
for (var i = 0; i < messageContent.length; i++) {
if (recentMessages[i].timestamp
.toDate()
.toLocal()
.hour == hour.hour) {}
}
return {
'content': messageContent,
'timestamp': timestamp.toDate().toLocal()};
});
}
I'm using the flutter_calendar_carousel package for my planner app. I'm getting the data from firestore so it shows up for like 2 seconds and then I get this error "package:flutter/src/widgets/container.dart': Failed assertion: line 316 pos 15: 'padding == null || padding.isNonNegative': is not true."
This is my code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_calendar_carousel/flutter_calendar_carousel.dart' show CalendarCarousel;
import 'package:flutter_calendar_carousel/classes/event.dart';
import 'package:flutter_calendar_carousel/classes/event_list.dart';
import 'package:intl/intl.dart' show DateFormat;
bool onDarkMode = false;
class MonthPageTest extends StatefulWidget {
#override
_MonthPageTestState createState() => _MonthPageTestState();
}
class _MonthPageTestState extends State<MonthPageTest> {
final databaseReference = Firestore.instance.collection("Planerino").document("UserSettings");
final databaseRef = Firestore.instance.collection("Eventhmonth");
darkmode() async{
try {
databaseReference.updateData({'Darkmode': onDarkMode});
}catch (e) {
print(e.toString());
}
}
#override
void initState(){
super.initState();
}
#override
void dispose(){
super.dispose();
}
toggleButton(){
setState(() {
onDarkMode = !onDarkMode;
});
darkmode();
}
//calender
DateTime _currentDate = DateTime.now();
static Widget _eventIcon = new Container(
width: 40.0,
height: 40.0,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(1000)),
border: Border.all(color: Colors.blue, width: 6.0)),
child: new Icon(
Icons.person,
color: Colors.amber,
size: 40.0,
),
);
//function
EventList<Event> _markedDateMap = new EventList<Event>(
events: {
new DateTime(2020, 6, 24): [
new Event(
date: new DateTime(2020, 6, 13),
icon: _eventIcon,
dot: Container(
margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
color: Colors.red,
),
),
],
},
);
Widget builderino(BuildContext context){
return StreamBuilder(
stream: databaseRef.snapshots(),
builder: (context, dataSnapshot){
var ref = dataSnapshot.data.documents;
for (var i = 0; i < ref.length; i++) {
String valueString = ref[i]['color'].split('(0x')[1].split(')')[0];
int value = int.parse(valueString, radix: 16);
Color newColor = new Color(value);
_markedDateMap.add(new DateTime(ref[i]['year'], ref[i]['month'], ref[i]['day']),
Event(
date: new DateTime(2020, 6, 13),
icon: _eventIcon,
dot: Container(
child: Padding(
padding: EdgeInsets.only(top: 90.0),
child: Container( alignment: Alignment.center, child: Text(ref[i]['description'], style: TextStyle(fontSize: 15.0, fontWeight: FontWeight.w300), textAlign: TextAlign.center,)),
),
margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
decoration: BoxDecoration(color: newColor),
),
));
}
return CalendarCarousel<Event>(
onDayPressed: (DateTime date, List<Event> events) {
this.setState(() => _currentDate = date);
events.forEach((event) => print(event.title));
},
weekendTextStyle: TextStyle(
color: Colors.red,
fontSize: 28.0,
),
markedDatesMap: _markedDateMap,
markedDateIconBuilder: (event) {
return event.dot;
},
showIconBehindDayText: true,
markedDateShowIcon: true,
markedDateIconMaxShown: 1000,
todayButtonColor: Colors.black12,
markedDateMoreShowTotal: true,
headerTextStyle: TextStyle(fontSize: 34.0, color: Colors.blue[300]),
daysTextStyle: TextStyle(fontSize: 28.0, color: onDarkMode ? Colors.white : Colors.black45),
todayTextStyle: TextStyle(fontSize: 28.0, color: onDarkMode ? Colors.white : Colors.black45),
weekdayTextStyle: TextStyle(fontSize: 28.0),
);
}
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: onDarkMode ? Colors.black87 : Colors.white,
margin: EdgeInsets.symmetric(horizontal: 16.0),
child: builderino(context),
),
);
}
}
Do i need to make it async or what is the problem?
from this SO answer
TLDR
Flutter has a sophisticated but effective algorithm for rendering its widgets. Margins and Paddings are analyzed at runtime, and the final size and position of the widget is determined. When you try to issue a negative margin you are purposefully creating a not valid layout where a widget is somehow dropping out of the space it is supposed to occupy.
Consider reading the doc here.
I have a Text() widget and a TextFormField() widget with TextInputType.number. What I want is when a user is typing in the TextFormField() subtraction math should be happening in real-time.
The value entered in the TextFormField() should subtract the value inside the Text() widget automatically as the user is typing numbers inside the TextFormField();
Note The final result should be shown in the same Text() widget as all of this typing and subtraction is happening.
import 'package:flutter/material.dart';
class ChangeValuesPage extends StatefulWidget {
#override
_ChangeValuesPageState createState() {
return _ChangeValuesPageState();
}
}
class _ChangeValuesPageState extends State<ChangeValuesPage> {
final pureNumbers = RegExp(r'^[0-9]+$');
int numberValue = 200;
int latestNumberValue;
final formKey = new GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appbar(context, 'Simple App', 'otherData'),
drawer: TopDrawer(),
body: SingleChildScrollView(
child: new Card(
child: Padding(
padding: EdgeInsets.all(5.0),
child: new Column(
children: <Widget>[
/**
* Below is the Text() field where subtraction math should occure.
*/
/// The value in the Text() widget should be subtracted automatically with
/// the number values inside the TextFormField() widget automatically as the user is typing the numbers
Text(
'Number value text: ${this.numberValue}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 6,
),
new Form(
key: formKey,
child: new Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.number,
decoration: new InputDecoration(
labelText: 'Reduce number value?',
hintText: 'Default number value is "0"',
),
validator: (val) {
if (val.isEmpty == true) {
return 'Fill in number values';
}
if (pureNumbers.hasMatch(val) == false) {
return 'Use alphanumeric characters only in nickname';
}
return null;
},
onSaved: (val) => this.latestNumberValue = int.parse(val),
),
],
),
),
],
),
),
),
),
);
}
}
I have tried different ways to achieve this but nothing is working. Thank you, posted with Love.
Try implementing this for onChanged property of the TextFormField. Hope this is what you are trying to achieve.
onChanged: (val) {
if (val.isEmpty) {
setState(() => numberValue = 200);
} else {
numberValue = 200;
setState(() => numberValue -= int.parse(val));
}
},
I have a stopwatch and would like to have a single button that both pauses and starts it. I am struggling with the logic around this. When printing to the console, the boolean is stuck on false, and won't let me re-click the button.
stopwatch.dart:
class NewStopWatch extends StatefulWidget {
#override
_NewStopWatchState createState() => new _NewStopWatchState();
}
class _NewStopWatchState extends State<NewStopWatch> {
Stopwatch watch = new Stopwatch();
Timer timer;
bool startStop = true;
String elapsedTime = '';
updateTime(Timer timer) {
if (watch.isRunning) {
setState(() {
startStop = false;
print("startstop Inside=$startStop");
elapsedTime = transformMilliSeconds(watch.elapsedMilliseconds);
});
}
}
#override
Widget build(BuildContext context) {
return new Container(
padding: EdgeInsets.all(20.0),
child: new Column(
children: <Widget>[
new Text(elapsedTime, style: new TextStyle(fontSize: 25.0)),
SizedBox(height: 20.0),
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new FloatingActionButton(
heroTag: "btn1",
backgroundColor: Colors.red,
onPressed: startOrStop(),
child: new Icon(Icons.pause)),
SizedBox(width: 20.0),
new FloatingActionButton(
heroTag: "btn2",
backgroundColor: Colors.green,
onPressed: resetWatch,
child: new Icon(Icons.check)),
],
)
],
));
}
startOrStop() {
print("startstop=$startStop");
if(startStop == true) {
startWatch();
} else {
stopWatch();
}
}
startWatch() {
startStop = true;
watch.start();
timer = new Timer.periodic(new Duration(milliseconds: 100), updateTime);
}
stopWatch() {
startStop = false;
watch.stop();
setTime();
startStop = true;
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
int hours = (minutes / 60).truncate();
String hoursStr = (hours % 60).toString().padLeft(2, '0');
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$hoursStr:$minutesStr:$secondsStr";
}
}
When the first button is clicked the first time, the stopwatch should start running. When it is clicked the second time, it should pause it.
I solved your code by adding setState() in your start and stop watch methods, flipped the logic in said methods, and added () => before startOrStop in the onPressed callback (This was the dealbreaker).
Furthermore, I removed startStop = false; from updateTimer(). I simplified your startOrStop() if statement as you do not need to write == true when checking the boolean value, you can simply write if(startStop) when evaluating booleans.
Working example:
import 'dart:async';
import 'package:flutter/material.dart';
class NewStopWatch extends StatefulWidget {
#override
_NewStopWatchState createState() => _NewStopWatchState();
}
class _NewStopWatchState extends State<NewStopWatch> {
Stopwatch watch = Stopwatch();
Timer timer;
bool startStop = true;
String elapsedTime = '';
updateTime(Timer timer) {
if (watch.isRunning) {
setState(() {
print("startstop Inside=$startStop");
elapsedTime = transformMilliSeconds(watch.elapsedMilliseconds);
});
}
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
Text(elapsedTime, style: TextStyle(fontSize: 25.0)),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
heroTag: "btn1",
backgroundColor: Colors.red,
onPressed: () => startOrStop(),
child: Icon(Icons.pause)),
SizedBox(width: 20.0),
FloatingActionButton(
heroTag: "btn2",
backgroundColor: Colors.green,
onPressed: null, //resetWatch,
child: Icon(Icons.check)),
],
)
],
),
);
}
startOrStop() {
if(startStop) {
startWatch();
} else {
stopWatch();
}
}
startWatch() {
setState(() {
startStop = false;
watch.start();
timer = Timer.periodic(Duration(milliseconds: 100), updateTime);
});
}
stopWatch() {
setState(() {
startStop = true;
watch.stop();
setTime();
});
}
setTime() {
var timeSoFar = watch.elapsedMilliseconds;
setState(() {
elapsedTime = transformMilliSeconds(timeSoFar);
});
}
transformMilliSeconds(int milliseconds) {
int hundreds = (milliseconds / 10).truncate();
int seconds = (hundreds / 100).truncate();
int minutes = (seconds / 60).truncate();
int hours = (minutes / 60).truncate();
String hoursStr = (hours % 60).toString().padLeft(2, '0');
String minutesStr = (minutes % 60).toString().padLeft(2, '0');
String secondsStr = (seconds % 60).toString().padLeft(2, '0');
return "$hoursStr:$minutesStr:$secondsStr";
}
}
Thanks for the working example. That helped me solve a similar problem.
In case it helps anyone, I added a few bits to flarkmarup's code so that the Icon's more relate to the flow.
At the top I added a variable:
IconData btnPlayStatus = Icons.play_arrow;
In FloatingActionButton (btn1) I replaced the Icon with the variable like:
child: Icon(btnPlayStatus)),
Then added SetState to startOrStop like:
startOrStop() {
if(startStop) {
setState(() {
btnPlayStatus = Icons.pause;
});
startWatch();
} else {
setState(() {
btnPlayStatus = Icons.play_arrow;
});
stopWatch();
}
}
i have some buttons that i need to be able to press only one and the rest should change their colour,
in order to make the code smaller i extracted the widget to make it reusable, but when i select a button it get the colour changed but it does not refresh the state of the other buttons.
if i dont extract the button method and make use of duplicate code inside the Row, then it works.
What im missing?
int numOfTime = 60;
class NumOfTime extends StatefulWidget {
const NumOfTime({
Key key,
}) : super(key: key);
#override
_NumOfTimeState createState() => _NumOfTimeState();
}
class _NumOfTimeState extends State<NumOfTime> {
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 15, top: 5),
child: Text(
'Δευτερόλεπτα',
style: TextStyle(color: Colors.white),
)),
Container(
margin: EdgeInsets.only(top: 2, left: 10, right: 10, bottom: 10),
decoration: myBoxDecoration(),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10, right: 5),
child: Icon(Icons.timer)),
CustomButton(
number: 30,
),
CustomButton(
number: 45,
),
CustomButton(
number: 60,
),
CustomButton(
number: 75,
),
CustomButton(
number: 90,
),
Container(
padding: EdgeInsets.only(right: 10),
)
],
),
),
],
);
}
}
class CustomButton extends StatefulWidget {
final int number;
const CustomButton({
Key key,
final int number,
}) : this.number = number;
#override
_CustomButtonState createState() => _CustomButtonState(number);
}
class _CustomButtonState extends State<CustomButton> {
final int number;
_CustomButtonState(this.number);
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Expanded(
flex: 1,
child: FlatButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(6.0)),
disabledColor: number == numOfTime ? Colors.black : Colors.white,
highlightColor: number == numOfTime ? Colors.black : Colors.white,
color: number == numOfTime ? Colors.black : Colors.white,
child: Text(
'$number',
style: TextStyle(
color: number == numOfTime ? Colors.white : Colors.black,
fontSize: 13),
),
onPressed: () {
numOfTime = number;
setState(() {});
}),
);
}
}
i expect to see all the other buttons change their color back to white if one is selected.
i also tried to pass null onPressed to make it disabled, but i dont see any change.
It's a common error, you have many options to solve this, I will show you the easy way with minimum modifications.
You need to refresh the parent widget ( the widget which contains the buttons) , because you need to refresh all of your buttons again.
So, this is your code fixed:
class _NumOfTimeState extends State<NumOfTime> {
_onPressed() {
setState(() {});
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: EdgeInsets.only(left: 15, top: 5),
child: Text(
'Δευτερόλεπτα',
style: TextStyle(color: Colors.white),
)),
Container(
margin: EdgeInsets.only(top: 2, left: 10, right: 10, bottom: 10),
//decoration: myBoxDecoration(),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10, right: 5),
child: Icon(Icons.timer)),
CustomButton(
number: 30,
onButtonPressed: _onPressed,
),
CustomButton(
number: 45,
onButtonPressed: _onPressed,
),
CustomButton(
number: 60,
onButtonPressed: _onPressed,
),
CustomButton(
number: 75,
onButtonPressed: _onPressed,
),
CustomButton(
number: 90,
onButtonPressed: _onPressed,
),
Container(
padding: EdgeInsets.only(right: 10),
)
],
),
),
],
);
}
}
class CustomButton extends StatefulWidget {
final int number;
final VoidCallback onButtonPressed;
const CustomButton({
Key key,
final int number,
this.onButtonPressed,
}) : this.number = number;
#override
_CustomButtonState createState() => _CustomButtonState(number);
}
class _CustomButtonState extends State<CustomButton> {
final int number;
_CustomButtonState(this.number);
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Expanded(
flex: 1,
child: FlatButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(6.0)),
disabledColor: number == numOfTime ? Colors.black : Colors.white,
highlightColor: number == numOfTime ? Colors.black : Colors.white,
color: number == numOfTime ? Colors.black : Colors.white,
child: Text(
'$number',
style: TextStyle(
color: number == numOfTime ? Colors.white : Colors.black,
fontSize: 13),
),
onPressed: () {
numOfTime = number;
widget.onButtonPressed();
}),
);
}
}
You can use streams that you subscribe to in your button. I wrote an article for this exact problem here.
Basically when one button is tapped you broadcast it's id on a stream. At the same time all your buttons (your CustomWidget) listens to the stream. When a new id comes on the stream you check if the current button is the one pressed, if it's not you disable it. If it is you leave it enabled.
Too much code to paste here, but the article (only 2 minutes long) describes everything.