Related
I am using flutter I want to change the color of a particular card when I tap on it, not all the cards at the same time. The code is attached below. I am glad if someone helps.
...
Widget options(context,String title,String subtitle,String price,
String info, String plan) {
return GestureDetector(
child: Container(
height: 166,
width: 119,
child: Card(
color: Colors.white,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Container(
width: 120,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(7),
topRight: const Radius.circular(7),
),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 8, top: 8),
child: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(255, 255, 255, 1),
fontSize: 15,
fontFamily: 'CeroPro',
fontWeight: FontWeight.bold),
),
),
),
)
],
),
),
),
);
}
}
...
You could use a stateful widget.
So it would look something like this
class MyCard extends StatefulWidget {
MyCard(this.title, this.subtitle, this.price, this.info, this.plan);
String title;
String subtitle;
String price;
String info;
String plan;
#override
_MyCardState createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> {
// initial color
Color color = Colors.white;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
//where newColor is the color it turns to
color = newColor;
});
},
child: Container(
height: 166,
width: 119,
child: Card(
// color is now a variable
color: color,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Container(
width: 120,
decoration: BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(7),
topRight: const Radius.circular(7),
),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 8, top: 8),
child: Text(
// to access the stateful widget's parameters, use widget.<parameter>
widget.title,
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(255, 255, 255, 1),
fontSize: 15,
fontFamily: 'CeroPro',
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
);
}
}
You can try this also:
import 'package:flutter/material.dart';
class Testing extends StatefulWidget {
const Testing({Key? key}) : super(key: key);
#override
State<Testing> createState() => _TestingState();
}
class _TestingState extends State<Testing> {
bool isColor1Changed = false;
bool isColor2Changed = false;
bool isColor3Changed = false;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
child: Row(
children: [
GestureDetector(
onTap: () {
setState(() {
isColor1Changed = !isColor1Changed;
});
},
child: options(context, "POPULAR", "Monthly", "\$4.99",
"3 Days Free Trail", "plan", isColor1Changed),
),
const SizedBox(width: 6),
GestureDetector(
onTap: () {
setState(() {
isColor2Changed = !isColor2Changed;
});
},
child: options(context, "83% OFF", "YEARLY", "\$9.99",
"\$0.83 / MONTH", "plan", isColor2Changed),
),
const SizedBox(width: 6),
GestureDetector(
onTap: () {
setState(() {
isColor3Changed = !isColor3Changed;
});
},
child: options(context, "50% OFF", "LIFE TIME", "\$19.99",
"\$39.98", "plan", isColor3Changed),
),
],
),
);
}
Widget options(context, String title, String subtitle, String price,
String info, String plan, bool isChangeColor) {
return GestureDetector(
child: Container(
height: 166,
width: 119,
child: Card(
color: isChangeColor ? Colors.lightBlue : Colors.white,
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Container(
width: 120,
decoration: const BoxDecoration(
color: Colors.black,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(7),
topRight: Radius.circular(7),
),
),
child: Padding(
padding: const EdgeInsets.only(bottom: 8, top: 8),
child: Text(
title,
textAlign: TextAlign.center,
style: const TextStyle(
color: Color.fromRGBO(255, 255, 255, 1),
fontSize: 15,
fontFamily: 'CeroPro',
fontWeight: FontWeight.bold),
),
),
),
],
),
),
),
);
}
}
I use hive to store my data locally in expense tracker app. I have saved all expenses in a box called expenseBox. I have given each expense item a date and I want items with the same date to be grouped together and displayed separately. Is there a way to achieve this?
Thanks for your help!
BTW this is the code for my homescreen where I display the items.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:flutter_locales/flutter_locales.dart';
import '/models/expense.dart';
import '/widgets/expense_list_tile.dart';
import '/screens/add_expense_screen.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const routeName = '/home_page';
#override
_HomeScreenState createState() => _HomeScreenState();
}
enum SlidableAction {
edit,
delete,
}
class _HomeScreenState extends State<HomeScreen> {
late Box expenseBox;
late Box pocketBox;
bool isFabVisible = true;
#override
void initState() {
expenseBox = Hive.box<Expense>('expenses');
pocketBox = Hive.box<int>('pocket');
super.initState();
}
#override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: Hive.box<int>('pocket').listenable(),
builder: (context, Box<int> pocketBox, child) => Scaffold(
appBar: AppBar(
title: const LocaleText('appName'),
elevation: 0,
centerTitle: true,
),
body: NestedScrollView(
headerSliverBuilder: (context, _) => [
SliverAppBar(
expandedHeight: MediaQuery.of(context).size.height * 0.15,
flexibleSpace: FlexibleSpaceBar(
background: Container(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Row(
children: [
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const LocaleText(
'appName',
style: TextStyle(
fontSize: 14, color: Colors.white),
),
Text(
'${pocketBox.get('budget') ?? 0}',
style: const TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const LocaleText(
'income',
style: TextStyle(
fontSize: 14, color: Colors.white),
),
Text(
'${pocketBox.get('totalIncome') ?? 0}',
style: const TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const LocaleText(
'expense',
style: TextStyle(
fontSize: 14, color: Colors.white),
),
Text(
'${pocketBox.get('totalExpense') ?? 0}',
style: const TextStyle(
fontSize: 18,
color: Colors.white,
fontWeight: FontWeight.bold),
),
],
),
],
),
),
Expanded(child: Container()),
],
),
),
),
),
],
body: ValueListenableBuilder(
valueListenable: Hive.box<Expense>('expenses').listenable(),
builder: (context, Box<Expense> expensesBox, child) {
return NotificationListener<UserScrollNotification>(
onNotification: (notification) {
if (notification.direction == ScrollDirection.forward) {
if (!isFabVisible) setState(() => isFabVisible = true);
} else if (notification.direction ==
ScrollDirection.reverse) {
if (isFabVisible) setState(() => isFabVisible = false);
}
return true;
},
child: Scrollbar(
thickness: 5,
interactive: true,
child: ListView.separated(
separatorBuilder: (context, index) {
return const SizedBox();
},
itemCount: expenseBox.length,
itemBuilder: (context, index) {
final expense = expenseBox.getAt(index);
return ExpenseListTile(index: index, expense: expense);
},
),
),
);
},
),
),
floatingActionButton: isFabVisible
? FloatingActionButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => const AddExpenseScreen(
index: -1,
),
));
},
child: const Icon(Icons.add),
)
: null,
),
);
}
}
You can try this code.
import 'package:flutter/material.dart';
import 'package:sticky_grouped_list/sticky_grouped_list.dart';
class MyMissionList extends StatefulWidget {
#override
State<MyMissionList> createState() => _MyMissionListState();
}
class _MyMissionListState extends State<MyMissionList> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(150.0),
child: Container(
decoration: BoxDecoration(
color: AppColors.baseLightBlueColor,
// AppColors.blue,
borderRadius: BorderRadius.only(bottomRight: Radius.circular(30)),
),
child: Material(
color: AppColors.baseLightBlueColor,
elevation: 15,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.only(bottomRight: Radius.circular(30)),
),
child: Column(
children: [
AppBar(
backgroundColor: AppColors.baseLightBlueColor,
elevation: 0.0,
actions: [
Container(
padding: EdgeInsets.only(right: 20),
child: Image.asset(
"assets/Vector-2.png",
height: 5,
width: 22,
color: Colors.white,
)),
],
),
Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.only(left: 20),
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecoration(
color: AppColors.baseLightBlueColor,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Hello User123,",
style:
TextStyle(color: AppColors.white, fontSize: 15),
),
SizedBox(height: 10),
Text(
AppStrings.totalAmount,
// "Montant total :",
style:
TextStyle(color: AppColors.white, fontSize: 11),
),
Text(
"592,30 €",
style:
TextStyle(color: AppColors.white, fontSize: 25),
),
],
),
)
],
),
),
)),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(left:15.0,right: 15,top: 15),
child: Text("My Mission",style: TextStyle(
color: Color(0xff243656),
fontSize: 15,
fontWeight: FontWeight.w300),
),
),
Expanded(
child: StickyGroupedListView<Element, DateTime>(
elements: elements,
order: StickyGroupedListOrder.ASC,
groupBy: (Element element) =>
DateTime(element.date.year, element.date.month, element.date.day),
groupComparator: (DateTime value1, DateTime value2) =>
value2.compareTo(value1),
itemComparator: (Element element1, Element element2) =>
element1.date.compareTo(element2.date),
floatingHeader: false,
groupSeparatorBuilder: (Element element) => Container(
height: 50,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 220,
padding: EdgeInsets.only(left: 20,top: 20,bottom: 10),
child: Text(
'${element.heading}',
textAlign: TextAlign.start,
style: TextStyle(color: Color(0xff919AAA)),
),
),
],
),
),
itemBuilder: (_, Element element) {
return element.type
? GestureDetector(
onTap: () {
// Navigator.push(context, MaterialPageRoute(builder: (context)=> WaitingForValidation()));
},
child: Card(
elevation: 4,
margin: EdgeInsets.only(bottom: 15, right: 15, left: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Container(
height: 70,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: AppColors.white),
child: Row(
children: [
Container(
width: MediaQuery.of(context).size.width * 0.62,
height: 50,
padding: EdgeInsets.only(top: 10,left: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
element.subTitle +
'${element.date.day}/${element.date.month}/'
'${element.date.year}',
style: TextStyle(
//color:AppColors.grey
color: Color(0xff919AAA),
fontSize: 12,
fontWeight: FontWeight.w300),
),
SizedBox(height: 2,),
Text(
element.hotelName,
style: TextStyle(
//color:AppColors.grey
color: Color(0xff243656),
fontSize: 15,
fontWeight: FontWeight.w300),
),
],
),
),
Padding(
padding: const EdgeInsets.all(5.0),
child: Card(
elevation: 15.0,
shadowColor: Colors.blue[100],
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20.0))),
child: Container(
height: 30,
width: 80,
decoration: BoxDecoration(
// boxShadow: [BoxShadow(color: AppColors.grey, blurRadius: 20.0)],
borderRadius:
BorderRadius.circular(20.0),
gradient: LinearGradient(
colors: [
Colors.blue,
Colors.blue.shade900,
],
)),
child: MaterialButton(
onPressed: () {},
child: Text(
element.buttonText,
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.bold),
),
),
),
),
),
],
),
),
),
)
: Card(
elevation: 4,
margin: EdgeInsets.only(bottom: 15, right: 15, left: 15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Container(
height: 70,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
color: AppColors.white),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.62,
height: 50,
padding: EdgeInsets.only(top: 10,left: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
element.subTitle +
'${element.date.day}/${element.date.month}/'
'${element.date.year}',
style: TextStyle(
//color:AppColors.grey
color: Color(0xff919AAA),
fontSize: 12,
fontWeight: FontWeight.w300),
),
SizedBox(height: 2,),
Text(
element.hotelName,
style: TextStyle(
//color:AppColors.grey
color: Color(0xff243656),
fontSize: 15,
fontWeight: FontWeight.w300),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top:5.0,bottom: 5),
child: Container(
height: 30,
width: 95,
child: MaterialButton(
onPressed: () {},
child: Text(
element.buttonText,
style: TextStyle(
color: AppColors.green,
fontSize: 14,
fontWeight: FontWeight.bold),
),
),
),
)
],
),
),
);
},
),
),
],
),
);
}
}
class Element {
bool type;
DateTime date;
String hotelName;
String subTitle;
String heading;
String buttonText;
Element(this.date, this.type, this.hotelName, this.subTitle, this.heading,
this.buttonText);
}
List<Element> elements = <Element>[
Element(
DateTime(2020, 7, 22),
false,
"Rendez-vous equipe prod",
"Jeudi",
"Terminate",
"Terminate",
),
Element(
DateTime(2021, 10, 15),
false,
"Rendez-vous equipe prod",
"Jeudi",
"Terminate",
"Terminate",
),
Element(
DateTime(2021, 10, 15),
false,
"Rendez-vous equipe prod",
"Jeudi",
"Terminate",
/**/
"Terminate",
),
Element(
DateTime(2021, 12, 12),
true,
"Visite entrepot Villabe ",
"Mercredi",
"To Plan",
"To Plan",
),
];
I have a problem with My Flutter Project...
The Keyboar always Appear and Suddenly Disappear when I try to click the TextField..
But It's only happen in this Page...
here is the Code
import 'dart:io';
import 'package:chat_chat_8/service/auth.dart';
import 'package:chat_chat_8/theme/style.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:image_picker/image_picker.dart';
class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key);
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
TextEditingController txt_name = new TextEditingController();
TextEditingController txt_status = new TextEditingController();
final FirebaseAuth _auth = FirebaseAuth.instance;
ImagePicker picker = ImagePicker();
var stateCondition;
var profileImage;
File? uriImage;
#override
Widget build(BuildContext context) {
Widget PhotoProfile(String userImage) {
if (profileImage == null) {
profileImage = userImage;
}
return Container(
height: 197.53,
width: 197.53,
decoration: BoxDecoration(
image: DecorationImage(
image: profileImage == userImage
? NetworkImage(profileImage.toString())
: FileImage(uriImage as File) as ImageProvider,
fit: BoxFit.cover,
),
borderRadius: BorderRadius.circular(150),
border: Border.all(
width: 2,
color: Purple_sub,
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 42.18,
width: 42.18,
child: ElevatedButton(
onPressed: () async {
XFile? image =
await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
profileImage = File(image.path).toString();
uriImage = File(image.path);
});
}
},
style: ElevatedButton.styleFrom(
primary: Purple_sub,
shadowColor: Colors.black54,
padding: EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Icon(
Icons.mode_edit_outline_outlined,
color: Colors.white,
size: 25,
),
],
)),
)
],
));
}
Widget ConditionComboBox(var userCondition) {
if (stateCondition == null) {
stateCondition = userCondition;
}
return Container(
height: 55,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: Text_Field,
),
),
child: Padding(
padding: const EdgeInsets.all(13),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
focusColor: Colors.white,
value: stateCondition,
//elevation: 5,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff595555),
fontSize: 24,
),
//iconEnabledColor: Colors.black,
items: <String>[
'Available',
'Unavailable',
'Busy',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: TextStyle(
color: Color(0xff595555),
),
),
);
}).toList(),
hint: Text(
"Select your condition",
style: TextStyle(
color: Color(0xff595555),
fontSize: 14,
fontWeight: FontWeight.w500),
),
onChanged: (value) {
setState(() {
stateCondition = value;
});
},
),
),
),
);
}
Widget TextProfile(String userName, String userStatus) {
txt_name.text = userName;
txt_status.text = userStatus;
return Column(
children: <Widget>[
Container(
height: 56.67,
child: TextFormField(
controller: txt_name,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff595555),
fontSize: 24,
),
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Text_Field),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Purple_sub,
),
),
),
),
),
SizedBox(
height: 18.19,
),
Container(
height: 56.67,
child: TextFormField(
controller: txt_status,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff595555),
fontSize: 24,
),
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Text_Field),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(
color: Purple_sub,
),
),
),
),
),
],
);
}
Widget SaveButton() {
return Container(
height: 50,
width: MediaQuery.of(context).size.width,
child: ElevatedButton(
onPressed: () {
AuthMethod().updateUser(
_auth.currentUser!.uid,
txt_name.text,
uriImage != null ? uriImage as File : null,
txt_status.text,
stateCondition,
);
},
style: ElevatedButton.styleFrom(
primary: Purple_sub,
),
child: Text(
'Complete',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
),
);
}
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: MediaQuery.of(context).viewInsets,
child: Container(
padding: EdgeInsets.only(top: 51.32),
margin: EdgeInsets.symmetric(
horizontal: 22.55,
),
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("Users")
.doc(_auth.currentUser!.uid)
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Container();
}
return Container(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/logo_app.png',
height: 50,
width: 50.64,
),
SizedBox(
width: 11.25,
),
Text(
'Profile',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 27,
),
)
],
),
SizedBox(
height: 44,
),
PhotoProfile(
snapshot.data.data()["userImage"],
),
SizedBox(
height: 54.83,
),
TextProfile(
snapshot.data.data()["userName"],
snapshot.data.data()["userStatus"],
),
SizedBox(
height: 18.19,
),
ConditionComboBox(
snapshot.data.data()["userCondition"],
),
SizedBox(
height: 100.98,
),
SaveButton(),
SizedBox(
height: 65.79,
),
],
),
);
},
),
),
),
),
);
}
}
I've tries many ways to solve this matter such as like in google
but no works at all
And my senior also can not solve this problem
I hope Some body can help me to Solve this Problem
Thx
I think you have to get all of the widgets (except the scaffold) out of the build method.
i have a Flutter app which should show a counting down timer in an alert box for Phone code confirming (i need this timer to resend the code to my user when 60 second is up) , i start timer when i click on Confirm Button , but the problem is that the timer is not showing that he's going down he stills with a fixed value.
here is my alert box
Alert Box with timer NOT SHOWING COUNT DOWN
here is my timer Function :
int _counter = 60;
Timer _timer;
void _startTimer(){
_counter = 60;
if(_timer != null){
_timer.cancel();
}
_timer = Timer.periodic(Duration(seconds: 1), (timer){
setState(() {
(_counter > 0) ? _counter-- : _timer.cancel();
});
});
}
here is my alert Box code :
void alertD(BuildContext ctx) {
var alert = AlertDialog(
// title: Center(child:Text('Enter Code')),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
backgroundColor: Colors.grey[100],
elevation: 0.0,
content: Container(
height: 215,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 15),
child: Text(
'Enter Code',
style: TextStyle(
color: Colors.green[800],
fontWeight: FontWeight.bold,
fontSize: 16
),
)),
Container(
height: 70,
width: 180,
child: TextFormField(
style: TextStyle(fontSize: 20,fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.green, width: 0.0)),
),
keyboardType: TextInputType.number,
maxLength: 10,
),
),
SizedBox(
height: 1,
),
Text('00:$_counter'),
SizedBox(height: 15,)
,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {
Navigator.of(ctx).pushNamed(SignUpScreenSecond.routeName);
},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.green,
Colors.grey,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Validate',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.grey,
Colors.green,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Resend',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
)
],
), //new column child
],
),
));
showDialog(
context: ctx,
builder: (BuildContext c) {
return alert;
});
}
that's how i'm calling my alert dialog and my timer when i click Confirm Button :
onTap: () {
_startTimer;
alertD(context);
},
You can copy paste run full code below
You can use StreamBuilder and StreamController
AlertDialog content continually receive stream int from Timer
code snippet
StreamController<int> _events;
#override
initState() {
super.initState();
_events = new StreamController<int>();
_events.add(60);
}
...
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
(_counter > 0) ? _counter-- : _timer.cancel();
print(_counter);
_events.add(_counter);
});
...
content: StreamBuilder<int>(
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
...
Text('00:${snapshot.data.toString()}'),
working demo
full code
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
StreamController<int> _events;
#override
initState() {
super.initState();
_events = new StreamController<int>();
_events.add(60);
}
Timer _timer;
void _startTimer() {
_counter = 60;
if (_timer != null) {
_timer.cancel();
}
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
//setState(() {
(_counter > 0) ? _counter-- : _timer.cancel();
//});
print(_counter);
_events.add(_counter);
});
}
void alertD(BuildContext ctx) {
var alert = AlertDialog(
// title: Center(child:Text('Enter Code')),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0))),
backgroundColor: Colors.grey[100],
elevation: 0.0,
content: StreamBuilder<int>(
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print(snapshot.data.toString());
return Container(
height: 215,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(
top: 10, left: 10, right: 10, bottom: 15),
child: Text(
'Enter Code',
style: TextStyle(
color: Colors.green[800],
fontWeight: FontWeight.bold,
fontSize: 16),
)),
Container(
height: 70,
width: 180,
child: TextFormField(
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.green, width: 0.0)),
),
keyboardType: TextInputType.number,
maxLength: 10,
),
),
SizedBox(
height: 1,
),
Text('00:${snapshot.data.toString()}'),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {
//Navigator.of(ctx).pushNamed(SignUpScreenSecond.routeName);
},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.green,
Colors.grey,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Validate',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(25),
child: Material(
child: InkWell(
onTap: () {},
child: Container(
width: 100,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
gradient: LinearGradient(
colors: [
Colors.grey,
Colors.green,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight),
),
child: Center(
child: Text(
'Resend',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
)),
),
),
),
)
],
), //new column child
],
),
);
}));
showDialog(
context: ctx,
builder: (BuildContext c) {
return alert;
});
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () {
_startTimer();
alertD(context);
},
child: Text('Click')),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
So this is the main code where I fetch the data from json and update my UI.
I have placed" //Area of Interest " comments where the code related to the problem lies.
class MainScreen extends StatefulWidget {
final curLocdata;
MainScreen({this.curLocdata});
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
Weather weather = Weather();
var cityName;
int temp;
int temp_min;
int temp_max;
Icon weatherIcon;
//Area of Interest 1
RotateAnimatedTextKit textSum;//created a widget of RotateAnimatedTextKit library.
String st;
//Area of Interest 2
#override
void initState() {
// TODO: implement initState
super.initState();
updateUI(widget.curLocdata);//calling update function to rebuild my UI state with new data
}
void updateUI(data) {
setState(() {
if (data == null) {
temp = 0;
cityName = 'Error';
weatherIcon = Icon(Icons.error);
return;
}
cityName = data['name'];
temp = data['main']['temp'].toInt();
temp_min = data['main']['temp_min'].toInt();
temp_max = data['main']['temp_max'].toInt();
var condition = data['weather'][0]['id'];
weatherIcon = weather.getIcon(condition);
textSum = weather.getMessage(temp);//Area of Interest 3
st = weather.subtext(condition);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: SafeArea(
child: Column(
children: <Widget>[
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
FlatButton(
onPressed: () async {
updateUI(await Network().getData());
},
child: Icon(
FontAwesomeIcons.locationArrow,
),
),
SizedBox(
width: 180.0,
child: TextLiquidFill(
waveDuration: Duration(seconds: 3),
loadDuration: Duration(seconds: 10),
text: 'OpenWeather',
waveColor: Colors.red,
boxBackgroundColor: Color(0xFF1B1B1D),
textStyle: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
fontFamily: 'Source Sans Pro',
),
boxHeight: 50.0,
),
),
FlatButton(
onPressed: () async {
String SName = await Navigator.push(context,
MaterialPageRoute(builder: (context) {
return Search();
}));
if (SName != null) {
updateUI(await Network().getDataName(
SName));
}
},
child: Icon(
Icons.add,
color: Colors.white,
size: 40,
),
),
],
),
),
Padding(
padding: EdgeInsets.fromLTRB(50, 50, 50, 0),
child: Row(
children: <Widget>[
SizedBox(
// margin: EdgeInsets.fromLTRB(0, 50, 260, 0),
child: TypewriterAnimatedTextKit(
totalRepeatCount: 200,
isRepeatingAnimation: true,
speed: Duration(milliseconds: 700),
text: [cityName,],
textAlign: TextAlign.left,
textStyle: TextStyle(
fontSize: 20,
fontFamily: 'Source Sans Pro',
),
),
),
],
)),
Expanded(
flex: 9,
child: Container(
margin: EdgeInsets.fromLTRB(50, 30, 50, 80),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
//mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
'$temp°',
style: TextStyle(
fontSize: 80,
fontWeight: FontWeight.bold,
fontFamily: 'Source Sans Pro',
),
),
),
),
Expanded(
flex: 2,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
st,
style: TextStyle(
fontSize: 30,
fontFamily: 'Source Sans Pro',
color: Colors.grey[500]),
),
),
),
Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 50),
child: Container(
child: textSum,//Used this textSum to show my animated text. problem
Area of Interest 4
),
),
Expanded(
child: SizedBox(
//width: double.infinity,
//height: 100,
child: Divider(
color: Colors.red,
),
),
),
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 38),
child: Text(
'$temp_min° - $temp_max°',
style: TextStyle(
fontSize: 20,
color: Colors.grey[500],
fontFamily: 'Source Sans Pro',
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.fromLTRB(20, 0, 0, 20),
//padding: const EdgeInsets.all(8.0),
child: AvatarGlow(
endRadius: 30.0, //required
child: Material(
//required
elevation: 0.0,
shape: CircleBorder(),
child: CircleAvatar(
//backgroundColor: Colors.grey[100],
child: weatherIcon
// radius: 40.0,
//shape: BoxShape.circle
),
),
),
),
)
],
)`enter code here`
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xFF0C0C0C),
),
),
),
Now the weather.dart file from where I am returning RotateAnimatedTextKit widget depending upon the condition
class Weather{
//This return RotateAnimatedTextKit which is then held by textSum and is put as a child inside a container in MainScreen
RotateAnimatedTextKit getMessage(int temp) {
if (temp > 25) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 40,
text: ['It\'s 🍦','time and','drink plenty','of water'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.topStart // or Alignment.topLeft
);
} else if (temp > 20) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 50,
text: ['Time for','shorts','👕','but keep','some warm','clothes handy'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart// or Alignment.topLeft
);
} else if (temp < 10) {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
totalRepeatCount: 200,
transitionHeight: 50,
text: ['You\'ll need','a 🧣','and','a 🧤','and a hot', 'soup and turkey'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart // or Alignment.topLeft
);
} else {
return RotateAnimatedTextKit(
isRepeatingAnimation: true,
transitionHeight: 50,
totalRepeatCount: 200,
text: ['Bring a','🧥','just in case','and also avoid', 'cold breeze','and cold drinks'],
textStyle: TextStyle(fontSize: 30.0, fontFamily: "Source Sans Pro", color: Colors.red),
textAlign: TextAlign.start,
alignment: AlignmentDirectional.bottomStart // or Alignment.topLeft
);
}
}
The thing is that the UI doesn't get updated even when the conditions are different. So any Solutions to why the widget tree is not updating? But it runs only the default text. Also, the cityName which is under the TextLiquidFill doesn't get updated.
Short answer:
Use Keys
Example:
import 'package:animated_text_kit/animated_text_kit.dart';
import 'package:flutter/material.dart';
class MyAnimatedText extends StatefulWidget {
const MyAnimatedText({Key? key}) : super(key: key);
#override
State<MyAnimatedText> createState() => _MyAnimatedTextState();
}
class _MyAnimatedTextState extends State<MyAnimatedText> {
bool isDarkMode = true;
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: isDarkMode ? Colors.grey[850] : Colors.amber[300]),
child: Column(
children: [
Container(
alignment: Alignment.topRight,
child: IconButton(
onPressed: () {
setState(() {
isDarkMode = !isDarkMode;
});
},
icon: Icon(isDarkMode ? Icons.light_mode : Icons.dark_mode))),
Padding(
padding: const EdgeInsets.all(15.0),
child: AnimatedTextKit(
key: ValueKey<bool>(isDarkMode),
animatedTexts: [
TypewriterAnimatedText(
isDarkMode ? 'Have a nice evening ;)' : 'Have a nice day :)',
cursor: isDarkMode ?'>':'<',
textStyle: TextStyle(
fontSize: 38,
color: isDarkMode ? Colors.amber[300] : Colors.grey[850]),
speed: const Duration(milliseconds: 100),
),
],
),
),
],
),
);
}
}
Result:
Background Information
I faced the same problem, when I tried to implement a dark / light change. The background color was defined in an other widget and changed, the font color was defined in the TypewriterAnimatedText Widget and only changed in the second loop. The color was not changing in the runnig animation.
Solution: use Keys
The Animation does not change beacause Flutter tries to keep the state of an StatefulWidget and the AnimatedTextKit is a Stateful Widget.
To force a rebuild you can use a Key.
a nice article can be found here: How to force a Widget to redraw in Flutter?
You can use WidgetsBinding.instance.addPostFrameCallback
For detail, you can reference https://www.didierboelens.com/faq/week2/
code snippet
#override
void initState(){
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
updateUI(widget.curLocdata);
});
}