setState not updating - flutter

I just can't figure out what is the problem with this set state method in flutter. Everything seems okay. But the text is not updating on onPressed.
class NetBalanceWidget extends StatefulWidget {
#override
_NetBalanceWidgetState createState() => _NetBalanceWidgetState();
}
class _NetBalanceWidgetState extends State<NetBalanceWidget> {
#override
Widget build(BuildContext context) {
String text = 'NetBalance-Amount';
return RawMaterialButton(
onPressed: () {
setState(() {
text = 'It works';
});
},
child: Container(
height: 80.0,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(text),
Text('0.00'),
],
),
),
),
);
}
}

You have text as a local variable in the build method. setState is essentially just calling build again, and is resetting the value of text back to its default of 'NetBalance-Amount'.
Move its declaration outside of build:
class _NetBalanceWidgetState extends State<NetBalanceWidget> {
String text = 'NetBalance-Amount';
#override
Widget build(BuildContext context) {
return RawMaterialButton(
onPressed: () {
setState(() {
text = 'It works';
});
},
child: Container(
height: 80.0,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(text),
Text('0.00'),
],
),
),
),
);
}
}

Related

Call method from onPressed of an IconButton

I have an IconButton and in the onPressed() method I want to call a void method that receives an incremental number as a parameter when the Button is clicked, then when obtaining this value it must call another void which calculates the days of weeks.
I have tested the function and if I put the values ​​in hard it does work, however when I put it in the widget it always returns the same value and does not change, no matter how much I put the setState method, I don't know how to increase said value.
Here I attach part of the code:
import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
class ExampleScreen extends StatefulWidget {
final String? text1;
final String? text2;
final String? text3;
const ExampleScreen({Key? key,
this.text1,
this.text2,
this.text3}
) : super(key: key);
#override
State<ExampleScreen> createState() => _ExampleScreenState();
}
class _ExampleScreenState extends State<ExampleScreen> {
int counter = 1;
void increase(){
counter++;
setState(() {
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.fromLTRB(10,0,0,0),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
_calendar(widget.text1,widget.text2,widget.text3,counter)
],
),
//),
),
)
);
}
}
_calendar(text1,text2,text3, int counter) => Container(
width: 250,
height: 50,
margin: const EdgeInsets.fromLTRB(50,0,0,0),
alignment: Alignment.center,
child: Wrap(
children:[
Container(
height: 225,
width: 225,
child: Column(
children: [
const SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconButton(
onPressed: () {
//When I call the function increase it tells me that the function is not declared
calculation_days(counter);
print('amount : $counter');
},
icon:const Icon(Icons.arrow_back_ios_new_outlined,size: 10)
),
const Text('Title',style: TextStyle(fontSize: 12)),
IconButton(
onPressed: () {},
icon:const Icon(Icons.arrow_forward_ios_outlined,size: 10)
),
],
),
]
),
),
]
)
);
void calculation_days(int week)
{
int firstday;
List<String> days;
List<String> daysxWeek;
days=findPreviousSaturdays1(count: week);
firstday= int.parse(days[week-1]);
daysxWeek=[firstday.toString()];
daysxWeek.add(firstday.toString());
}
since you declare it inside the StatefulWidget, not the State, you need to access it inside your onPressed method like this:
widget.increase()
IconButton(
onPressed: () {
widget.increase(); // call it like this.
},
icon:const Icon(Icons.arrow_back_ios_new_outlined,size: 10)
);
Another solution is that you can move your increase() from StatefulWidget to the State class, then you can use it by calling increase() instead of widget.increase().

How to make TextFormField enabled by a button?

I want to make TextFormField enabled by press a button which is not in the same level,how to pass the value from the button?
return Scaffold(
child:Column(
children:[
Container(
child: Row(
children[
Textbutton(),
.......//otherButtons
]
)
),
DefaultTabController(
child: Column(
children[
TabBar(),
TabBarView(
child:Column(
children[
TextFormField(),
.......//otherTextFormFields
]
)
)
]
)
)
]
)
);
You can set text through TextEditingController. and to disable user input, use readOnly:true. You can test the widget and get the concept how it works.
class ColorTest extends StatefulWidget {
ColorTest({Key? key}) : super(key: key);
#override
State<ColorTest> createState() => _ColorTestState();
}
class _ColorTestState extends State<ColorTest> {
TextEditingController controller = TextEditingController();
bool readOnly = true;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
TextButton(
onPressed: () {
controller.text = "Got the text from button click";
setState(() {});
},
child: Text("set text"),
),
TextFormField(
controller: controller,
readOnly: readOnly,
),
TextButton(
onPressed: () {
readOnly = !readOnly;
setState(() {});
},
child: Text("ReadOnlyMode: $readOnly"),
),
],
)
// materialButto(),
),
);
}
}

Can I random to show SizeBox widget?

I want to show SizeBox widget by random. when I open this class it should be random to show Size Box 1 first or Size Box 2 first.
class Page extends StatelessWidget {
var random = new Random();
int randomNumber;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
randomNumber = random.nextInt(1);
if(randomNumber == 1){
/////////////////////////////////////// Size box 1 ////////////////////////////////////
SizedBox(
child: TextButton(
onPressed: () {
AlertDialog(
title: Text('a'),
content: Text('a'));
},
child: Image.asset('images/test.jpg'),
)),
}else{
/////////////////////////////////////// Size box 2 ////////////////////////////////////
SizedBox(
child: TextButton(
onPressed: () {
AlertDialog(
title: Text('b'),
content: Text('b'));
},
child: Image.asset('images/test2.jpg'),
)),
}
I try to use randomNumber = random.nextInt(1) in children: <Widget>[] but it show
The element type 'int' can't be assigned to the list type 'Widget'.dart(list_element_type_not_assignable)
It seems I cannot write dart code in widget. Can I random to show SizeBox widget ?
The error occurs because you called randomNumber = random.nextInt(1); inside the Row children. Since randomNumber is of type int and not of type Widget you can't do this. One way to fix this is to create a StatefulWidget and set the randomNumber in initState method.
By the way using if/else inside children of Row/Column you don't put the curly brackets {}.
import 'package:flutter/material.dart';
import 'dart:math';
class Page extends StatefulWidget {
#override
_Page createState() => _Page();
}
class _Page extends State<Page> {
var random = new Random();
int randomNumber;
#override
void initState(){
randomNumber = random.nextInt(1);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
if (randomNumber == 1)
/////////////////////////////////////// Size box 1 ////////////////////////////////////
SizedBox(
child: TextButton(
onPressed: () {
AlertDialog(title: Text('a'), content: Text('a'));
},
child: Image.asset('images/test.jpg'),
),
)
else
/////////////////////////////////////// Size box 2 ////////////////////////////////////
SizedBox(
child: TextButton(
onPressed: () {
AlertDialog(title: Text('b'), content: Text('b'));
},
child: Image.asset('images/test2.jpg'),
),
),
],
),
),
],
),
),
);
}
}

Listview scrolling and selecting Textfield afterwards is freezing my app

I am using the package
country_code_picker: ^1.4.0
https://pub.dev/packages/country_code_picker#-installing-tab-
with flutter 1.17.3
Which is pretty much one of the only country code picker packages. But I have one serious problem an I don't have a clue what it could be.
When I run this code
import 'package:flutter/material.dart';
import 'package:country_code_picker/country_code_picker.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
App();
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: TestWidget(),
);
}
}
class TestWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(body: _buildCountryPicker(context));
}
Widget _buildCountryPicker(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: CountryCodePicker(
initialSelection: 'NL',
),
),
);
}
}
And I open the dialog to select a country. I scroll in the list and then select the TextField my keyboard opens and when I try to type something my entire app freezes. I can't even hot reload. I don't get a single error.
I am running this on my Huawei P30, but I also experience this on other android devices. I don't know if this is a flutter bug or a country code picker bug.
I think it is probably in this widget somewhere. If anyone could point me in the right direction it would help me alot!
class SelectionDialog extends StatefulWidget {
final List<CountryCode> elements;
final bool showCountryOnly;
final InputDecoration searchDecoration;
final TextStyle searchStyle;
final TextStyle textStyle;
final WidgetBuilder emptySearchBuilder;
final bool showFlag;
final double flagWidth;
final Size size;
final bool hideSearch;
/// elements passed as favorite
final List<CountryCode> favoriteElements;
SelectionDialog(
this.elements,
this.favoriteElements, {
Key key,
this.showCountryOnly,
this.emptySearchBuilder,
InputDecoration searchDecoration = const InputDecoration(),
this.searchStyle,
this.textStyle,
this.showFlag,
this.flagWidth = 32,
this.size,
this.hideSearch = false,
}) : assert(searchDecoration != null, 'searchDecoration must not be null!'),
this.searchDecoration =
searchDecoration.copyWith(prefixIcon: Icon(Icons.search)),
super(key: key);
#override
State<StatefulWidget> createState() => _SelectionDialogState();
}
class _SelectionDialogState extends State<SelectionDialog> {
/// this is useful for filtering purpose
List<CountryCode> filteredElements;
#override
Widget build(BuildContext context) => SimpleDialog(
titlePadding: const EdgeInsets.all(0),
title: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
IconButton(
padding: const EdgeInsets.all(0),
iconSize: 20,
icon: Icon(
Icons.close,
),
onPressed: () => Navigator.pop(context),
),
if (!widget.hideSearch)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: TextField(
style: widget.searchStyle,
decoration: widget.searchDecoration,
onChanged: _filterElements,
),
),
],
),
children: [
Container(
width: widget.size?.width ?? MediaQuery.of(context).size.width,
height:
widget.size?.height ?? MediaQuery.of(context).size.height * 0.7,
child: ListView(
children: [
widget.favoriteElements.isEmpty
? const DecoratedBox(decoration: BoxDecoration())
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...widget.favoriteElements.map(
(f) => SimpleDialogOption(
child: _buildOption(f),
onPressed: () {
_selectItem(f);
},
),
),
const Divider(),
],
),
if (filteredElements.isEmpty)
_buildEmptySearchWidget(context)
else
...filteredElements.map(
(e) => SimpleDialogOption(
key: Key(e.toLongString()),
child: _buildOption(e),
onPressed: () {
_selectItem(e);
},
),
),
],
),
),
],
);
Widget _buildOption(CountryCode e) {
return Container(
width: 400,
child: Flex(
direction: Axis.horizontal,
children: <Widget>[
if (widget.showFlag)
Flexible(
child: Padding(
padding: const EdgeInsets.only(right: 16.0),
child: Image.asset(
e.flagUri,
package: 'country_code_picker',
width: widget.flagWidth,
),
),
),
Expanded(
flex: 4,
child: Text(
widget.showCountryOnly
? e.toCountryStringOnly()
: e.toLongString(),
overflow: TextOverflow.fade,
style: widget.textStyle,
),
),
],
),
);
}
Widget _buildEmptySearchWidget(BuildContext context) {
if (widget.emptySearchBuilder != null) {
return widget.emptySearchBuilder(context);
}
return Center(
child: Text('No country found'),
);
}
#override
void initState() {
filteredElements = widget.elements;
super.initState();
}
void _filterElements(String s) {
s = s.toUpperCase();
setState(() {
filteredElements = widget.elements
.where((e) =>
e.code.contains(s) ||
e.dialCode.contains(s) ||
e.name.toUpperCase().contains(s))
.toList();
});
}
void _selectItem(CountryCode e) {
Navigator.pop(context, e);
}
}
Also filed an issue on the flutter github https://github.com/flutter/flutter/issues/59886
Edit:
I have a video of it right here
https://www.youtube.com/watch?v=669KitFG9ek&feature=youtu.be
I just had to remove the keys, so there probably was a duplicate key
...filteredElements.map(
(e) => SimpleDialogOption(
//key: Key(e.toLongString()),
child: _buildOption(e),
onPressed: () {
_selectItem(e);
},
),
),

Flutter: Calling SetState() from another class

I am trying to make a simple image that appears or disappears when a button is pushed. This button resides in a separate class to the image, so in Flutter this creates a massive headache of an issue.
I have read many forums on this and I have tried all the solutions posed but none of them are working for me.
What I am trying to do:
class SinglePlayerMode extends StatefulWidget {
#override
SinglePlayerModeParentState createState() => SinglePlayerModeParentState();
}
class SinglePlayerModeParentState extends State<SinglePlayerMode> {\
bool coinVisible = false;
toggleCoin() {
setState(() {
coinVisible = !coinVisible;
});
}
Widget topMenuRow() {
return Stack(
children: [
Column(
children: [
coinVisible == true ?
Padding(
padding: EdgeInsets.all(50),
child: Container(
height: 60,
width: 60,
color: Colors.blueGrey[0],
decoration: BoxDecoration(
color: Colors.blueAccent,
image: DecorationImage(
image: ExactAssetImage('lib/images/coin_head.jpg'),
fit: BoxFit.cover,
),
),
),
) : Container(
height: 60,
width: 60,
color: Colors.black,
),
],
),
],
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
child: ListView(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
children: [
topMenuRow(),
SizedBox(height: 40),
],
),
),
);
}
And this is the separate class which I would like to trigger the SetState() on coinVisible from:
class dropDownMenu extends StatefulWidget { #override
_dropDownMenuState createState() => _dropDownMenuState();
}
class _dropDownMenuState extends State<dropDownMenu> {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget> [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
child: Opacity(
opacity: 0.0,
child: FloatingActionButton(
heroTag: null,
onPressed: (){
//SOMEHOW CALL SetState() ON coinVisble HERE!
},
),
),
);
}
}
But nothing I have tried is working, and I have lost hours.
It simple, you need to send your SinglePlayMode::toggleCoin function as callback to dropDownMenu class.
class dropDownMenu extends StatefulWidget {
final _callback; // callback reference holder
//you will pass the callback here in constructor
dropDownMenu( {#required void toggleCoinCallback() } ) :
_callback = toggleCoinCallback;
#override
_dropDownMenuState createState() => _dropDownMenuState();
}
class _dropDownMenuState extends State<dropDownMenu> {
#override
Widget build(BuildContext context) {
return Stack(
children: <Widget> [
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
child: Opacity(
opacity: 0.0,
child: FloatingActionButton(
heroTag: null,
onPressed: (){
widget?._callback(); // callback calling
},
),
),
);
}
}
Then when you create a dropDownMenu class instance in your SinglePlayerMode class you will do
dropDownMenu(
toggleCoinCallback: toogleCoin,
);