Related
I have a favorite button in a gridview.builder, but i want when i click a particular favorite button (it turns to red) and others wont turn... cos when i click a particular favorite button it affects all. I need help on how to solve it.
i am new to flutter.
Please i will like someone to mentor me...i seriously need a mentor(Please anyone)
class HomeItemsWidget extends StatefulWidget {
const HomeItemsWidget({
Key? key,
}) : super(key: key);
#override
State<HomeItemsWidget> createState() => _HomeItemsWidgetState();
}
class _HomeItemsWidgetState extends State<HomeItemsWidget> {
bool isIconView = false;
`your text`
#override
Widget build(BuildContext context) {
return GridView.builder(
itemCount: gridImages.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
mainAxisExtent: 231.5,
crossAxisCount: 2),
itemBuilder: (BuildContext context, int index) {
return Container(
decoration: BoxDecoration(`your text`
color: Appcolors.whiteColor,
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.only(left: 12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconButton(
onPressed: () {
toggleIconView();
},
icon: Icon(isIconView ? Icons.favorite : Icons.favorite_border),
color: isIconView ? Colors.red : Colors.red ,
),
Align(
alignment: Alignment.center,
child: Image.asset(
"${gridImages[index]["image"]}",
height: 70.0,
),
),
const SizedBox(height: 20.0),
Text(
"${gridImages[index]["heading"]}",
style: GoogleFonts.poppins(
color: Appcolors.primaryColor,
fontSize: 12.0,
fontWeight: FontWeight.w500),
),
const SizedBox(height: 4.0),
Text(
"${gridImages[index]["title"]}",
style: GoogleFonts.poppins(
color: Appcolors.greyColor,
fontSize: 16.0,
fontWeight: FontWeight.w600),
),
const SizedBox(height: 12.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${gridImages[index]["price"]}",
style: GoogleFonts.poppins(
color: Appcolors.darkGreyColor,
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
],
),
),
);
},
);
}
void toggleIconView() {
setState(() {
isIconView = !isIconView;
});
}
}
i want when i click a particular favorite button (it turns to red) and others wont turn
You need to use List to track N-number of items. You can do
class _HomeItemsWidgetState extends State<HomeItemsWidget> {
List<int> selectedItem = [];
And to get and set color based on current state
IconButton(
onPressed: () {
toggleIconView(index);
},
icon: Icon(selectedItem.contains(index)
? Icons.favorite
: Icons.favorite_border),
color: selectedItem.contains(index) ? Colors.red : Colors.red,
),
And toggle option will be
void toggleIconView(int index) {
if (selectedItem.contains(index)) {
selectedItem.remove(index);
} else {
selectedItem.add(index);
}
setState(() {});
}
Hey guys I'm working on some project and need to create a custom dropdown,
like this
I am able to make that here is the code, the code is messy but I will refactor it once I make it work. Or if you have some other way how I can accomplish this I'm open to suggestions.
GlobalKey? actionKey = GlobalKey();
List<String> picked = [];
List<IconData> icons = [
Icons.blur_circular_outlined,
Icons.sports_basketball,
Icons.sports_baseball_sharp,
Icons.sports_tennis_rounded,
Icons.people,
];
List<String> sports = [
"Fudbal",
"Kosarka",
"Tenis",
"Stoni tenis",
"Kuglanje"
];
List<int> ints = [0, 1, 2, 3, 4];
List<bool> booles = [false, false, false, false, false];
OverlayEntry? overlayEntry;
var position;
double? y;
double? x;
void findDropdownData() {
RenderBox renderBox =
actionKey!.currentContext!.findRenderObject() as RenderBox;
position = renderBox.localToGlobal(Offset.zero);
y = position!.dy;
x = position!.dx;
}
OverlayEntry _overlayEntryBuilder() {
return OverlayEntry(
builder: (context) {
return Positioned(
// top: position,
left: 16.w,
right: 16.w,
child: Material(
child: dropdownExpanded(),
),
);
},
);
}
Widget buildRows(i) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 17.w, vertical: 15.h),
child: Row(
children: [
SizedBox(
height: 24.h,
width: 24.w,
child: Checkbox(
activeColor: style.purpleMain,
value: booles[i],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4)),
onChanged: (value) {
setState(() {
booles[i] = value!;
booles[i] == true
? picked.add(sports[i])
: picked.remove(sports[i]);
});
},
),
),
SizedBox(
width: 10.w,
),
Text(
sports[i],
style: TextStyle(
color: booles[i] == true ? style.purpleMain : Colors.grey,
),
),
const Spacer(),
Icon(
icons[i],
color: booles[i] == true ? style.purpleMain : Colors.grey,
size: 15,
),
],
),
);
}
Widget dropdown() {
return GestureDetector(
key: actionKey,
onTap: () {
setState(() {
isPressed = !isPressed;
});
if (isPressed == false) {
overlayEntry = _overlayEntryBuilder();
Overlay.of(context)!.insert(overlayEntry!);
}
},
child: Container(
width: double.infinity,
height: 50.h,
decoration: BoxDecoration(
border: Border.all(color: style.e8e8e8),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.only(left: 16.w, right: 13.w),
child: Row(
children: [
picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
const Spacer(),
const Icon(
Icons.arrow_drop_down,
color: style.bdbdbd,
),
],
),
),
);
}
Widget pickedEmpty() {
return Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(
fontSize: 16.sp,
color: style.bdbdbd,
fontWeight: FontWeight.w400,
),
);
}
Widget pickedNotEmpty() {
List<Widget> list = <Widget>[];
for (var i = 0; i < picked.length; i++) {
list.add(
Padding(
padding: EdgeInsets.only(right: 5.w),
child: Text(
picked[i],
style: TextStyle(
fontSize: 16.sp,
color: style.bdbdbd,
fontWeight: FontWeight.w400,
),
),
),
);
}
return Row(children: list);
}
Widget dropdownExpanded() {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: style.purpleMain),
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
GestureDetector(
onTap: () {
setState(() {
isPressed = !isPressed;
});
overlayEntry?.remove();
},
child: Container(
width: double.infinity,
height: 50.h,
padding: EdgeInsets.only(left: 16.w, right: 13.w),
child: Row(
children: [
picked.isEmpty ? pickedEmpty() : pickedNotEmpty(),
const Spacer(),
const Icon(
Icons.arrow_drop_up,
color: style.bdbdbd,
),
],
),
),
),
const Divider(
height: 0,
thickness: 1,
color: style.e8e8e8,
indent: 17,
endIndent: 17,
),
Column(
children: [
for (int i in ints) buildRows(i),
],
),
],
),
);
}
Here are results
This is what I want to accomplish
So I just want to move down this expanded dropdown and how to update these booles in the overlay if I don't use overlay it's working as it should but I need to open that dropdown on the top of another content. Thanks for the help.
Use smart_select it is fully customizable and you can achieve the design you want easily using this library.
Updated Answer
Regarding the UI, it is like an Expansions Tile Widget in flutter. You can implement that dropdown with expansions tile and pass list of items in children,
for expand, collapse tile after select each item, you can create a global key and control that in UI.
final GlobalKey<AppExpansionTileState> expansionTile = new GlobalKey();
collapse → expansionTile.currentState.collapse();
ExpansionTile(
title: Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
),
children: <Widget>[
// put items here
],
),
smaple :
Widget customDropDown() => Container(
// color: Colors.white,
padding: const EdgeInsets.all(10),
child: ListTileTheme(
dense: true,
child: ExpansionTile(
title: const Text(
"Možete obeležiti više aktivnosti",
style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w500),
),
children: <Widget>[
Container(
width: double.infinity,
decoration: const BoxDecoration(
color: Colors.white,
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(20))),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: const [
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("something"),
)
],
),
),
)
],
),
),
);
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: SafeArea(
child: Stack(
children: [pageDesign(), customDropDown()],
),
),
),
);
}
fakeWidget(color) => Container(
height: 100,
width: double.infinity,
color: color,
child: const Center(
child: Text("widget1"),
),
);
Widget pageDesign() => Column(
children: [
/* you should control this size in diffrent orientation and for big size
device to handle responsive
*/
const SizedBox(
height: 80,
),
fakeWidget(
Colors.green,
),
fakeWidget(
Colors.yellow,
),
fakeWidget(
Colors.orange,
),
fakeWidget(
Colors.blue,
),
],
);
i m creating an application in which i have to change the state of a button save the state. and afterwards when that page is open again then the changed state should be displayed.
for example: if i click on the favorite button then its state gets changed from unselected to selected so after this when i closed the app and open it again then the favorite button should be in selected state rather than in unselected state.
please help me out with this issue.
i have used a variable is which the value is stored and then i m checking the condition .
import 'package:EventsApp/Models/EventModel.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:favorite_button/favorite_button.dart';
import 'package:shared_preferences/shared_preferences.dart';
class DetailPage extends StatefulWidget {
final String image;
final EventModel value;
const DetailPage({Key key, this.image, #required this.value})
: super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
String eventId;
String userId;
bool isPartcipated = false;
bool isfavorite;
Future<http.Response> participateinEvent() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var uid = prefs.getString('userId');
var eveid = prefs.getString('eventId');
var res = await http.post(
'http://10.0.2.2:8080/eventusermapping/addParticipant/' +
uid +
'/' +
eveid);
print(res.body);
Fluttertoast.showToast(
msg: 'Participation Successful',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
);
}
Future<http.Response> addfavorite() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var uid = prefs.getString('userId');
var eveid = prefs.getString('eventId');
var res = await http
.post('http://10.0.2.2:8080/event/addtoFavorites/' + uid + '/' + eveid);
Fluttertoast.showToast(
msg: 'Added to favorite',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
);
setState(() {
isfavorite = true;
});
}
Future<http.Response> removefavorite() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var uid = prefs.getString('userId');
var eveid = prefs.getString('eventId');
var res = await http.post(
'http://10.0.2.2:8080/event/removeFromFavorites/' + uid + '/' + eveid);
Fluttertoast.showToast(
msg: 'Removed from favorite',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
);
setState(() {
isfavorite = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Color(0xffffffff)),
onPressed: () => Navigator.of(context).pop(),
),
centerTitle: true,
backgroundColor: Colors.lightBlue[900],
elevation: 0.0,
title: new Text("Event Details",
style: const TextStyle(
color: const Color(0xffffffff),
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
fontSize: 19.0)),
),
body: Container(
child: SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
height: 400.0,
child: Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
bottom: 90,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('${widget.value.coverimg}'),
fit: BoxFit.fitWidth,
),
),
// child: Column(
// children: [
// IconButton(
// icon: Icon(Icons.arrow_back),
// onPressed: () => Navigator.pop(context),
// iconSize: 30.0,
// color: Colors.lightBlue[900],
// ),
// ],
// ),
),
),
Positioned(
top: 270,
left: 20,
right: 20,
bottom: 0,
child: Card(
elevation: 0.5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25.0),
),
child: Padding(
padding: EdgeInsets.all(15.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
'${widget.value.name}',
style: TextStyle(
fontSize: 23.0,
fontWeight: FontWeight.bold,
color: Colors.lightBlue[900]),
),
],
),
Row(
children: [
Icon(
Icons.location_on,
color: Colors.grey,
size: 20,
),
SizedBox(width: 12.0),
Text(
" Kalyan west",
style: TextStyle(
fontSize: 18,
color: Colors.lightBlue[900]),
),
],
),
Row(
children: [
Icon(
Icons.calendar_today,
color: Colors.grey,
size: 20,
),
SizedBox(width: 12.0),
Text(
'${widget.value.date}',
style: TextStyle(
fontSize: 17,
color: Colors.lightBlue[900]),
),
],
),
],
),
),
),
),
],
),
),
Container(
width: double.infinity,
child: Column(
children: [
SizedBox(height: 12.0),
ListTile(
leading: CircleAvatar(
radius: 25,
backgroundImage:
NetworkImage('${widget.value.eventheadphoto}'),
),
title: Text(
'${widget.value.eventheadname}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.lightBlue[900]),
),
subtitle: Text(
"Event Head",
style: TextStyle(fontSize: 17, color: Colors.grey),
),
),
SizedBox(height: 15.0),
Padding(
padding: EdgeInsets.symmetric(horizontal: 18),
child: Text(
'${widget.value.description}',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 19, color: Colors.lightBlue[900]),
),
),
SizedBox(height: 20.0),
Container(
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(left: 70.0),
child: Center(
child: SizedBox(
width: 190,
child: isPartcipated
? RaisedButton(
onPressed: null,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(30.0)),
color: Colors.grey,
child: Text(
"Participated",
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
letterSpacing: 1.5),
),
disabledColor: Colors.black12,
disabledElevation: 1,
disabledTextColor: Colors.black,
)
: RaisedButton(
onPressed: () {
participateinEvent();
setState(() {
isPartcipated = !isPartcipated;
});
},
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(30.0)),
color: Colors.lightBlue[900],
child: Text(
"Participate",
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
letterSpacing: 1.5),
),
),
),
),
),
Padding(
padding: EdgeInsets.only(left: 50.0),
child: Container(
decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(50),
// color: Colors.blue,
// border:
// Border.all(width: 1, color: Colors.grey),
),
child: FavoriteButton(
isFavorite: false,
valueChanged: (isfavorite) {
if (isfavorite) {
addfavorite();
} else {
removefavorite();
}
},
), //IconButton(
// iconSize: 35,
// color: Colors.redAccent[400],
// icon: Icon(Icons.favorite_border),
// tooltip: 'Add to Favorite',
// onPressed: () {}),
),
)
],
),
),
SizedBox(height: 30.0)
],
),
)
],
),
),
),
);
}
}
You not storing the button state in addFavourite method.
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('stateOfButton', true);
When you open your app again, you can get the button state like how you get for the userId and eventId.
prefs.getBool('stateOfButton');
I don't know if it's possible to just rewrite the initial value of the variables for the following executions of the app. What is possible to do is to store this values somehow, and load them before loading the screen with the favorite button.
What i would do is to use path provider(https://pub.dev/packages/path_provider) and store something like(lets suppose we are talking about movies)
"user":{
"favorited movies" : [
12
23
]
}
and then before loading the button, checking the movie id is in the user favorited movies array. You can find a good example of how exactly would you store in the complete example in https://flutter.dev/docs/cookbook/persistence/reading-writing-files
If you think about the standard way to deal with State management in your app I suggest you look into BLoC. It requires an initial learning curve with it but it is worth it.
Feel free to find more info in the 'Counter' example on the website
https://bloclibrary.dev/#/gettingstarted
Here is another good talk by Felix, who maintains bloc library
https://www.youtube.com/watch?v=knMvKPKBzGE&t=2327s
you can use this package flutter shared preferences
you should make get and set methods
class StorageService {
Future<String> getTokenAsync() async {
SharedPreferences instances = await getInstanceAsync();
String stringValue = instances.getString(Constant.userToken);
return stringValue; }
Future<void> setTokenAsync(String token) async {
SharedPreferences instances = await getInstanceAsync();
instances.setString(Constant.userToken, token); } }
String token = await _storageService.getTokenAsync();
_storageService.setTokenAsync(entity.token);
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);
});
}
I am having a hard time figuring this one out (im still new to flutter btw), I created a new screen with form that lets the user fill it out with information and after filling them out, there is a validator and onSaved: on EACH TextFormField() as of the moment, I just want the textform fields to have the datas saved to Firebase Database.
EDIT: I managed to make it work somehow using this code BUT the data Ive input in is nulled in Firebase database (second pic):
child: FlatButton(
color: Colors.blue,
child: Text("Confirm", style: TextStyle(color: Colors.white)),
onPressed: () async {
await db.collection("createdoffers").add(
{
'name': offerName,
'type': offerType,
'start': start,
'end': end,
}
);
},
),
Ive also watched some tutorial but Im having trouble making it work since its kind of a bit different to what Im trying to do (I guess its a beginners problem, Im new to programming and I fell in love with flutter lol)
Now on my Firebase console, I created a new collection with some new
dummy data just to fill in (mind you, I still dont save INPUTS from
the app, just created a collection and put in some dummy data)
The image of my firebase is below:
NULLED data
my code is below for the screen form that I am trying to save data from INPUTS in the TextFormField and saving it all to my database by clicking the FlatButton
My target for this is: 1. Save the data to firebase 2. Read that data and display it to a Container widget, I just want the C and R in CRUD for now
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class AddOffer extends StatefulWidget {
AddOffer({Key key}) : super(key: key);
#override
_AddOfferState createState() => _AddOfferState();
}
class _AddOfferState extends State<AddOffer> {
String offerName;
String offerType;
String start;
String end;
bool allBranches = false;
bool selectedBranches = false;
final db = Firestore.instance;
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: ListView(
children: <Widget>[
Container(
color: Color(0xFF707070),
height: 200.0,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
InkWell(
onTap: () {
setState(() {
Navigator.pop(context);
});
},
child: Padding(
padding: EdgeInsets.fromLTRB(20, 30, 20, 0),
child: Icon(Icons.arrow_back,
color: Colors.white, size: 25.0),
),
),
Center(
child: Padding(
padding: EdgeInsets.all(80.0),
child: Text(
"DEAL IMAGE",
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
),
],
),
),
Form(
key: _formKey,
child: Padding(
padding: EdgeInsets.fromLTRB(30, 30, 30, 0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text(
"Name",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
],
),
TextFormField(
decoration: InputDecoration(hintText: 'Enter Offer Name'),
validator: (value) {
if (value.isEmpty) {
}
return 'Please Enter Offer Name';
},
onSaved: (value) => offerName = value,
),
SizedBox(height: 30.0),
Row(
children: <Widget>[
Text(
"Type",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
],
),
TextFormField(
decoration: InputDecoration(hintText: 'Enter Offer Type'),
validator: (value) {
if (value.isEmpty) {
}
return 'Please Enter Offer Type';
},
onSaved: (value) => offerType = value,
),
SizedBox(height: 60.0),
Row(
children: <Widget>[
Text(
"Start",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
],
),
TextFormField(
decoration:
InputDecoration(hintText: 'Enter Offer Start Date'),
validator: (value) {
if (value.isEmpty) {
}
return 'Please Enter Offer Start Date';
},
onSaved: (value) => offerName = value,
),
SizedBox(height: 30.0),
Row(
children: <Widget>[
Text(
"End",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
],
),
TextFormField(
decoration:
InputDecoration(hintText: 'Enter Offer End Date'),
validator: (value) {
if (value.isEmpty) {
}
return 'Please Enter Offer End Date';
},
onSaved: (value) => offerName = value,
),
SizedBox(height: 60.0),
Row(
children: <Widget>[
Column(
children: <Widget>[
Text(
"Valid Until",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
Text(
"01/01/20",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
],
),
SizedBox(height: 30.0),
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Time of Active",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
Text(
"12/12/19",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
],
),
SizedBox(height: 60.0),
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Max people (optional)",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
Text(
"5",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
],
),
SizedBox(height: 20.0),
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Max redemption per member (optional)",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
Text(
"5",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
],
),
SizedBox(height: 20.0),
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Number of redemption",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
Text(
"5",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
],
),
SizedBox(height: 60.0),
Row(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Branches",
style: TextStyle(
color: Color(0xFF707070),
fontSize: 17.0,
fontWeight: FontWeight.bold),
),
SizedBox(height: 5.0),
Row(
children: <Widget>[
Checkbox(
value: allBranches,
onChanged: (bool value) {
setState(() {
allBranches = value;
});
},
),
Text(
"All Branches",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
Row(
children: <Widget>[
Checkbox(
value: selectedBranches,
onChanged: (bool value) {
setState(() {
selectedBranches = value;
});
},
),
Text(
"Selected Branches",
style: TextStyle(
color: Color(0xFF707070), fontSize: 17.0),
),
],
),
],
),
],
),
SizedBox(height: 30.0),
Container(
width: 250.0,
child: FlatButton(
color: Colors.blue,
child: Text("Confirm", style: TextStyle(color: Colors.white)),
onPressed: () {
},
),
),
SizedBox(height: 30.0),
],
),
),
)
],
),
),
);
}
}
WHAT I TRIED SO FAR
child: FlatButton(
color: Colors.blue,
child: Text("Confirm", style: TextStyle(color: Colors.white)),
onPressed: () {
setState(() async{
await db.collection("createdoffers").add(
{
'name': offerName,
'type': offerType,
'start': start,
'end': end,
}
);
}
);
}
)
What Went Wrong
child: FlatButton(
color: Colors.blue,
child: Text("Confirm", style: TextStyle(color: Colors.white)),
onPressed: () async {
await db.collection("createdoffers").add(
{
'name': offerName, // This is null, try to change the way you save data via setState
'type': offerType,
'start': start,
'end': end,
}
);
},
),
What you can do
If you are continuing with this implementation, please do try TextEditingController.
// Declaration
TextEditingController _offerNameTextController = TextEditingController();
// Usage
TextFormField(
controller: _offerNameTextController,
...
)
// Retrieving data from the input field
FlatButton(
onPressed: () {
// Utilize the value (eg. on your Firebase saving method
print(_offerNameTextController.text);
}
)
Further reading
https://api.flutter.dev/flutter/widgets/TextEditingController-class.html
You're passing the value of the textformfield during onsaved. But you forgot to save the form. Add this _formKey.currentState.save();
child: FlatButton(
color: Colors.blue,
child: Text("Confirm", style: TextStyle(color: Colors.white)),
onPressed: () async {
_formKey.currentState.save();
await db.collection("createdoffers").add(
{
'name': offerName,
'type': offerType,
'start': start,
'end': end,
}
);
},
),