setState isn't referenced flutter 3.0 - android

I am working on a school project, since we updated the flutter version from 2.X to 3.0.1 we face this problem : setState isn't referenced. We do not understand as we are using this in a statefulWidget. We went to the internet to show what the problem is but we cannot find a way to make it work because most of the time it was because people where using a stateless widget which is not our case.
Start of file :
``` class PageProfilAmi extends StatefulWidget {
final User user;
final String? idRelation;
const PageProfilAmi({Key? key, required this.user, this.idRelation})
: super(key: key);
#override
_PageProfilAmiState createState() => _PageProfilAmiState();
}
class _PageProfilAmiState extends State<PageProfilAmi> {
IconData _icon = Icons.add;
#override
void initState() {
super.initState();
} ```
Where we have the issue :
``` IconButton(
onPressed: () {
setState() {
_icon = Icons.delete;
}
AuthController.deleteAmi(
widget.idRelation.toString());
},
icon: Icon(
_icon,
color: CustomColors.MAIN_PURPLE,
size: 20,
),
) ```

enter code hereHere issue is in syntax of setState
setState(() {
// code
});

You have setState written wrong. In a statefull widget setState is called like this:
setState(() {
//do something
});
Basically you are missing the outside parentheses '(' ')'

Related

My flutter property has not assign value in future block

My flutter property has not changed in future blocks. I tried setState(() {}) but not working.
I uninstalled flutterSdk and android SDK then I installed this SDK but still has not changed.
I had the same situation in my previous project. I copied the code of other pages and pasted it to the page that is not working. The page is working a little then page is wrong
this is my code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class apiPage extends StatefulWidget {
const apiPage({Key? key}) : super(key: key);
#override
State<apiPage> createState() => _apiPageState();
}
class _apiPageState extends State<apiPage> {
String _response="exe";//this property is not working
Future <void> ApiCall() async{
String adres="www.api";
http.Response cevap=await http.get(Uri.parse(adres));
if(cevap.statusCode==200){
_response=cevap.body;//property needs to be changed
}else{
_response="error";//feature needs to be changed
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Text('$_response'),
]
),
);
}
}
When you like to update UI with new value, call setState on widget-state class. Here you can do,
if(cevap.statusCode==200){
setState((){
_response=cevap.body;
});
}else{
setState((){
_response="error";
});
}
Make sure to call the ApiCall() method.
A better choice will be using FutureBuilder for future method. Find more about FutureBuilder and StatefulWidget.

Flutter Appbar disappears when using Share

When I use Share.share using Flutter share_plus package the app bar disappears and the content of the screen moves up...and it doesn't look very nice.
Simple example:
import 'package:flutter/material.dart';
import 'package:share_plus/share_plus.dart';
class Example extends StatelessWidget {
const Example({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
await Share.share('Some text');
},
child: const Text('Press me'),
);
}
}
Anyone knows why that happens?
Try SafeArea around Scaffold widget.
Try this out It works fine for me
final RenderBox box = context.findRenderObject() as RenderBox;
Share.share(shareURL,
subject: title,
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size);

Android Alarm Manager Plus in Flutter never fires oneShot

I am trying to get a handle on the nearly entirely undocumented Android Alarm Manager Plus, and have a very simple app to press a button, set an alarm, and fire the alarm as follows:
import 'package:flutter/material.dart';
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(const MyApp());
}
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.pink,
),
home: SetAlarmPage(),
);
}
}
class SetAlarmPage extends StatefulWidget {
const SetAlarmPage({Key? key}) : super(key: key);
#override
State<SetAlarmPage> createState() => _SetAlarmPageState();
}
class _SetAlarmPageState extends State<SetAlarmPage> {
String test = "Press Me!";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Set an Alarm")),
body: Center(
child: ElevatedButton(
child: Text(test),
onPressed: () {
print(test + " Button Pressed...");
setAlarm();
},
),
),
floatingActionButton:
FloatingActionButton(onPressed: null, child: Icon(Icons.add)),
);
}
void setAlarm() async {
print("setAlarm");
final int alarmID = 1;
await AndroidAlarmManager.oneShot(Duration(minutes: 1), alarmID, playAlarm);
}
void playAlarm() {
print("playAlarm");
setState(() {
test = "Pressed!";
});
}
}
I manage to get the alarm service started, but beyond that, nothing. I have tried initializing the AndroidAlarmManager object both in main and in setAlarm, tried moving around ensureInitialized, tried setting different durations in oneShot, tried changing the ID, and tried firing a more simple alarm function. No matter what I do, the alarm wont set or fire.
I'm pretty sure its something simple, but for a core function of android, there is no real documentation on how to use it to speak of.
Does anyone know what android alarm manager plus wants that I'm not providing, here?
first did you add the required AndroidManifest.xml tags?
second thing, by reading the documentation on https://pub.dev/packages/android_alarm_manager_plus, the callback is executed on a separate Isolate thus you can't pass a function from an instance class since isolates don't share memory (isolate is to run a piece of code on another thread).
You can make sure that the plugin is working by adding a static function with a print statement (you can't call setState from a static function)
change the playAlarm function into:
static void playAlarm() {
print("playAlarm");
}
this function is used to verify that the plugin is working

flutter) The status of the icon can't be changed immediately (Edit)

I made it possible to toggle the heart icon in the post like Instagram.
And I implemented it so that user information is uploaded to the firestore when I toggle the icon.
There is no problem with the 'Like' and 'Unlike' function of 'Like Icon', but there is one other problem.
There is a problem that the color of the icon does not change immediately when toggling the icon in the post. I can check that this icon has changed when I go to a different screen and come back in.
The following is the code for this icon. (I edited this code)
class LikeToggleIcon extends StatefulWidget {
final String postKey;
final PostModel postModel;
const LikeToggleIcon(
{Key key,
this.postKey,
this.postModel,
this.fromSearch,
this.searchResults})
: super(key: key);
#override
State<LikeToggleIcon> createState() => _LikeToggleIconState();
}
class _LikeToggleIconState extends State<LikeToggleIcon> {
// bool _isLiked = false;
#override
Widget build(BuildContext context) {
//get userModel
UserModel userModel =
Provider.of<UserModelState>(context, listen: false).userModel;
return IconButton(
onPressed: () {
// setState(() {
postNetworkRepo.toggleLike(
widget.postModel.postKey, userModel.userKey);
// });
},
icon: Icon(
widget.postModel.numOfLikes.contains(userModel.userKey)
? Icons.favorite_outlined
: Icons.favorite_border_outlined,
size: 27,
color: Colors.redAccent,
),
);
//toggle method
class PostNetworkRepo with Transformers {
Future<void> toggleLike(String postKey, String userKey) async {
final DocumentReference postRef =
Firestore.instance.collection(COLLECTION_POSTS).document(postKey);
final DocumentSnapshot postSnapshot = await postRef.get();
//check Post collection
if (postSnapshot.exists) {
//check already contain userKey
//if no contain upload userKey, else delete userKey (toggle Like/Unlike)
if (postSnapshot.data[KEY_NUMOFLIKES].contains(userKey)) {
postRef.updateData({
KEY_NUMOFLIKES: FieldValue.arrayRemove([userKey])
});
} else {
postRef.updateData({
KEY_NUMOFLIKES: FieldValue.arrayUnion([userKey])
});
}
}
}
}
PostNetworkRepo postNetworkRepo = PostNetworkRepo();
//This is the part of detail post screen.
class DetailScreen extends StatefulWidget {
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
#override
Widget build(BuildContext context) {
//get userModel
UserModel userModel =
Provider.of<UserModelState>(context, listen: false).userModel;
return Scaffold(
appBar: AppBar(
title: _postUser(),
actions: [
//toggle likeIcon
LikeToggleIcon(
postKey: widget.postKey,
postModel: widget.postModel,
),
],
),
I tried using setState() on the IconButton(), but the problem was not solved.
can I get help with this problem?
I believe you are using setState() to change value of variable that's inside the Widget and NOT the State of that widget.
You need to have variables that changes the Widget inside the state for it to be updated. Keeping it inside Widget won't change the Icon, unless the whole widget is recreated (like when you change the screen).
(correct me if I'm wrong. Providing full code of the widget could be more useful)

Flutter - setState not updating inner Stateful Widget

Basically I am trying to make an app whose content will be updated with an async function that takes information from a website, but when I do try to set the new state, it doesn't reload the new content. If I debug the app, it shows that the current content is the new one, but after "rebuilding" the whole widget, it doesn't show the new info.
Edit: loadData ( ) method, basically read a URL with http package, the URL contains a JSON file whose content changes every 5 minutes with new news. For example a .json file with sports real-time scoreboards whose scores are always changing, so the content should always change with new results.
class mainWidget extends StatefulWidget
{
State<StatefulWidget> createState() => new mainWidgetState();
}
class mainWidgetState extends State<mainWidget>
{
List<Widget> _data;
Timer timer;
Widget build(BuildContext context) {
return new ListView(
children: _data);
}
#override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) async {
String s = await loadData();
this.setState(() {
_data = <Widget> [new childWidget(s)];
});
});
}
}
class childWidget extends StatefulWidget {
childWidget(String s){
_title = s;
}
Widget _title;
createState() => new childState();
}
class childState extends State<gameCardS> {
Widget _title;
#override
Widget build(BuildContext context) {
return new GestureDetector(onTap: foo(),
child: new Card(child: new Text(_title));
}
initState()
{
super.initState();
_title = widget._title;
}
}
This should sort your problem out. Basically you always want your Widgets created in your build method hierarchy.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MaterialApp(home: new Scaffold(body: new MainWidget())));
class MainWidget extends StatefulWidget {
#override
State createState() => new MainWidgetState();
}
class MainWidgetState extends State<MainWidget> {
List<ItemData> _data = new List();
Timer timer;
Widget build(BuildContext context) {
return new ListView(children: _data.map((item) => new ChildWidget(item)).toList());
}
#override
void initState() {
super.initState();
timer = new Timer.periodic(new Duration(seconds: 2), (Timer timer) async {
ItemData data = await loadData();
this.setState(() {
_data = <ItemData>[data];
});
});
}
#override
void dispose() {
super.dispose();
timer.cancel();
}
static int testCount = 0;
Future<ItemData> loadData() async {
testCount++;
return new ItemData("Testing #$testCount");
}
}
class ChildWidget extends StatefulWidget {
ItemData _data;
ChildWidget(ItemData data) {
_data = data;
}
#override
State<ChildWidget> createState() => new ChildState();
}
class ChildState extends State<ChildWidget> {
#override
Widget build(BuildContext context) {
return new GestureDetector(onTap: () => foo(),
child: new Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: new Card(
child: new Container(
padding: const EdgeInsets.all(8.0),
child: new Text(widget._data.title),
),
),
)
);
}
foo() {
print("Card Tapped: " + widget._data.toString());
}
}
class ItemData {
final String title;
ItemData(this.title);
#override
String toString() {
return 'ItemData{title: $title}';
}
}
This was really giving me headache and no Google results were working. What finally worked was so simple. In your child build() assign the value to the local variable before you return. Once I did this everything worked with subsequent data loads. I even took out the initState() code.
Many thanks to #Simon. Your answer somehow inspired me to try this.
In your childState:
#override
Widget build(BuildContext context) {
_title = widget._title; // <<< ADDING THIS HERE IS THE FIX
return new GestureDetector(onTap: foo(),
child: new Card(child: new Text(_title));
}
Hopefully this works in your code. For me, I use a Map for the entire JSON record passed in, rather than a single String, but that should still work.
The Root issue explained
initState(), for the child widget, is called only once when the Widget is inserted into the tree. Because of this, your child Widget variables will never be updated when they change on the parent widget. Technically the variables for the widgets are changing, you are just not capturing that change in your state class.
build() is the method that gets called every time something in the Widget changes. This is the reason #gregthegeek solution works. Updating the variables inside the build method of your child widget will ensure they get the latest from parent.
Works
class ChildState extends State<ChildWidget> {
late String _title;
#override
Widget build(BuildContext context) {
_title = widget._title; // <==== IMPORTANT LINE
return new GestureDetector(onTap: () => foo(),
child: new Text(_title),
);
}
}
Does not work
(It will not update when _title changes in parent)
class ChildState extends State<ChildWidget> {
late String _title;
#override
void initState() {
super.initState();
_title = widget._title; // <==== IMPORTANT LINE
}
#override
Widget build(BuildContext context) {
return new GestureDetector(onTap: () => foo(),
child: new Text(_title),
);
}
}
I'm unsure why this happens when calling setState(...) in an async function, but one simple solution is to use:
WidgetsBinding.instance.addPostFrameCallback((_) => setState(...));
instead of just setState(...)
This fixed my issue... If you have an initial value to be assigned on a variable use it in initState()
Note : Faced this issue when I tried to set initial value inside build function.
#override
void initState() {
count = widget.initialValue.length; // Initial value
super.initState();
}
don't use a future within a future; use different function that will return each future individually like this
List<Requests> requestsData;
List<DocumentSnapshot> requestsDocumentData;
var docId;
#override
void initState() {
super.initState();
getRequestDocs();
}
Future<FirebaseUser> getData() {
var _auth = FirebaseAuth.instance;
return _auth.currentUser();
}
getRequestDocs() {
getData().then((FirebaseUser user) {
this.setState(() {
docId = user.uid;
});
});
FireDb()
.getDocuments("vendorsrequests")
.then((List<DocumentSnapshot> documentSnapshots) {
this.setState(() {
requestsDocumentData = documentSnapshots;
});
});
for (DocumentSnapshot request in requestsDocumentData) {
this.setState(() {
requestsData.add(Requests(
request.documentID,
request.data['requests'],
Icons.data_usage,
request.data['requests'][0],
"location",
"payMessage",
"budget",
"tokensRequired",
"date"));
});
}
}
you can create individual functions for
FireDb().getDocuments("vendorsrequests")
.then((List<DocumentSnapshot> documentSnapshots) {
this.setState(() {
requestsDocumentData = documentSnapshots;
});
});
and
for (DocumentSnapshot request in requestsDocumentData) {
this.setState(() {
requestsData.add(Requests(
request.documentID,
request.data['requests'],
Icons.data_usage,
request.data['requests'][0],
"location",
"payMessage",
"budget",
"tokensRequired",
"date"));
});
}
I found that the use of
this
with setState is must
The real issue on child StatefulWidget not rebuilding is in the KEY
Hey, I'm a bit late to the discussion, but I think this is important.
I was facing a similar problem a while back and I even came to this thread to get some ideas.
In my case, I was simply getting widget.value directly inside the build method of the childWidget, and it was not updating when i called setState in the mainWidget.
Then i found this video: https://youtu.be/kn0EOS-ZiIc
(When to Use Keys - Flutter Widgets 101 Ep. 4) -
Here the Google dev talks about how keys in Flutter.
The short answer is
In a StatefulWidget the actual value you pass is stored in the state, not in the widget itself, like a StatelessWidget does.
When you call setState in the mainWidget, Flutter walks down the widget tree and checks each childWidget's type and key, to see if anything has changed. As stateful widgets store their values in the state, Flutter thinks the child widgets did not change (because the types and keys are the same) and does not rebuild them, even if the value changed.
The real solution is to give the widget a key containing the value that is changing, so when Flutter is walking down the tree, it notices that the key changed, and rebuilds the stateful widget.
Other solutions here may work as well, but if you want to really understand it, this video is worth watching.
first check whether it is a stateless or stateful widget,and if the class is stateless then make it to a stateful widget and try adding a code after closing the
setState(() { _myState = newValue; });
In my case, it was just defining the state as a class property and not a local variable in the build method
Doing this -
List<Task> tasks = [
Task('Buy milk'),
Task('Buy eggs'),
Task('Buy bread'),
];
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) => TaskTile(
...
instead of this -
#override
Widget build(BuildContext context) {
List<Task> tasks = [
Task('Buy milk'),
Task('Buy eggs'),
Task('Buy bread'),
];
return ListView.builder(
itemBuilder: (context, index) => TaskTile(
...
Found the best solution.
If you are using a stateless widget you can't use set state, so just convert the stateless widget to statefull widget

Categories

Resources