I am creating a button but I want it change the text every time I press it (e.g. on and off).
This is my button class.
class TextSend extends StatelessWidget {
String title;
Function onTap;
TextSend(this.title, this.onTap);
#override
Widget build(BuildContext context) {
return RaisedButton(
color: Colors.green,
disabledColor: Colors.grey,
textColor: Colors.white,
disabledTextColor: Colors.black38,
child: title,
onPressed: onTap,
);
}
}
This is the button instance, where I call it on another class:
TextSend('Button on', Navigator.push(context, MaterialPageRoute(builder: (context) => MQTTView()));),
In order to change the text , you need to change the Stateless widget to Stateful Widget, because Stateless widget is only for static pages that doesn't change content.
after that in order to have a text into the button you need to give a Text widget as a child of the RaisedButton ,and not a String .
in order to change the text you have to call a function when the button is pressed, that function is gonna change the title variable and after that call "setState" function which is responsible of refreshing the page so that your changes can be displayed
here is your code modified and should do the job you want. if you miss something just make me know . thanks
import 'package:flutter/material.dart';
class TextSend extends StatefulWidget {
String title;
Function onTTap;
TextSend(this.title, this.onTTap);
#override
_TextSendState createState() => _TextSendState();
}
class _TextSendState extends State<TextSend> {
#override
Widget build(BuildContext context) {
return RaisedButton(
color: Colors.green,
disabledColor: Colors.grey,
textColor: Colors.white,
disabledTextColor: Colors.black38,
child: Text(widget.title),
onPressed: changeText, //
);
}
// method responsible of changing the text
changeText(){
setState(() {
widget.title='text changed';
});
}
}
You need a StatefulWidget class. Flutter documentation has a really nice tutorial that shows an example similar to your problem.
Related
For instance: I have a main IconButton using assets/image/button.png as an icon!
so when you click on it, it opens a pop-up window with smaller icons/images using the assets as well and from that pop-up, you can select IconButton to replace the main Image. So if you select one of the pictures from that pop-up it replaces the main Icon to that specific image. How would you implement that if you wanted to use your assets as buttons?
On separate Dart file I have main Image Container:
Container(
width: 100,
padding: EdgeInsets.only(bottom: 50),
child: MainIcon()
),
Code I have tried:
class MainIcon extends StatefulWidget {
const MainIcon({Key? key}) : super(key: key);
#override
State<MainIcon> createState() => _MainIcon();
}
class _MainIcon extends State<MainIcon> {
Widget build(BuildContext context) {
return Container(
child: IconButton(
icon: GetItems(),
iconSize: 150,
onPressed: () {
showShopItems();
},
));
}
//pop-up window for changing icons
Future showShopItems() => showDialog(
context: context,
builder: (context) => AlertDialog(
content: ShopItems(),
backgroundColor: Colors.transparent,
));
//change food icons
Image GetItems() {
if (Bag.isClicked = true) {
return Image.asset('assets/images/bag.png');
}
if (Shampoo.isClicked = true) {
return Image.asset('assets/images/shampoo.png');
}
if (lotion.isClicked == true) {
return Image.asset('assets/images/lotion.png');
} else {
return Image.asset('assets/images/cart.png');
}}}
What each widget button looks like:
class Bag extends StatefulWidget {
static bool isClicked = false;
const Bag({Key? key}) : super(key: key);
#override
State<Bag> createState() => _Bag();
}
class _Bag extends State<Bag> {
Widget build(BuildContext context) {
return Container(
child: IconButton(
icon: Image.asset('assets/images/bag.png'),
iconSize: 70,
onPressed: () {
Bag.isPressed == true;
});
print("bag is clicked");
},
));
}
}
I would try to give each button an id and when clicking on the corresponding button, assign the desired id to the big main button, and then call setState (() {}) to update the widget and it will change its image. Further, I would save this id to the Database and asynchronously load the value every time I log in to the application, you can use Flutter Secure Storage or Shared Preferences as the Database for application settings. If you have something more than just changing the image on the main button, for example, changing the link that the button leads to, then create models, then create a list of models with predefined values and use them.
So I am trying to create a custom widget in flutter that has multiple constructors.
Essentially I am creating an arrow button but want to be able to create the button with arrow icons facing in different directions.
Currently my code looks like this:
class RotateButton extends StatefulWidget {
RotateButton.left() {
_RotateButtonState createState() => _RotateButtonState.left();
}
RotateButton.right() {
_RotateButtonState createState() => _RotateButtonState.right();
}
#override
_RotateButtonState createState() => _RotateButtonState();
}
class _RotateButtonState extends State<RotateButton> {
IconData icon;
_RotateButtonState();
_RotateButtonState.left() {
icon = Icons.arrow_back;
}
_RotateButtonState.right() {
icon = Icons.arrow_forward;
}
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: kPrimaryColor,
borderRadius: BorderRadius.circular(20),
),
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Icon(
icon,
size: 70,
),
),
);
}
}
Every time I use my widget it just defaults to the default constructor and shows no Icon child.
Is there a way to build a class without making a default constructor.
Also is there a way I can build this widget without using a stateful widget as it kind of just overcomplicates it.
I am getting a message that says:
The declaration 'createState' isn't referenced
This message is coming up next to the named constructors in the rotatebutton class.
Any help is very much appreciated.
Use something like this:
class SomeWidget extends StatelessWidget {
final bool isRight;
const SomeWidget({Key key, this.isRight}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: Icon(isRight?Icons.arrow_forward:Icons.arrow_back),
);
}
}
I am making an app to search for some items on goggle.
While doing this search app shows a loading icon, after search is complete it goes to the second screen.
If I press go back to do another search, loading icon still running.
!isLoading ? FlatButton(
color: Colors.blue,
textColor: Colors.white,
disabledColor: Colors.grey,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
splashColor: Colors.blueAccent,
onPressed: () async{
String query = getQuery();
List<Recipe> receitas = await getReceitas(query);
Navigator.push(context, MaterialPageRoute(builder: (context)=>result_screen(receitas)));
setState(() {
isLoading = true;
});
},
child: Text('BUSCAR', style: TextStyle(fontSize: 15.0))):
Center(
child: CircularProgressIndicator(),
),
To solve this problem tried to use global variables, as explained in Global Variables in Dart but it didn't work.
globals.dart
library my_prj.globals;
bool isLoading;
main.dart
import 'globals.dart' as global;
!global.isLoading?FlatButton(...
setState(() {
global.isLoading = true;
});
result_screen.dart
import 'globals.dart' as global;
global.isLoading = false;
...
I can show more parts of my code if necessary.
You don't need global variable to achieve this use life cycle methods(deactivate())
class Temp extends StatefulWidget {
#override
_TempState createState() => _TempState();
}
class _TempState extends State<Temp> {
bool isLoading=false;
void deactivate() { //Life cycle method
isLoading=false;
super.deactivate();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.yellow,
),
);
}
}
This deactivate method will be called when this widget is popped or in normal terms when you navigate to a different page. In the deactivate method I have set isLoading=false, So when
you navigate to the next page isloading becomes false.
This is the warning:
This class (or a class which this class inherits from) is marked as '#immutable', but one or more of its instance fields are not final: MyWidget.myVar
The console tells me that the variable must be final. I suspect that I should change my widget to a stateful if I want to change variables, but to me it doesn't makes sense, as the code works as intended. When I change my variable I don't want to change anything on the screen, I just want to use it later.
What I'm doing is wrong? If not, how can I disable this warning?
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: MyWidget(),
),
);
}
class MyWidget extends StatelessWidget {
String myVar;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
MaterialButton(
child: Text('Click me do change variable'),
onPressed: () {
myVar = 'Clicked!';
},
),
MaterialButton(
child: Text('Click me to print the variable'),
onPressed: () {
print(myVar);
},
),
],
),
);
}
}
Your logic is correct and it doesn't really matter since you are not outputting anything on screen. However the best practise is to change it to a Stateful Widget.
It doesn't really affect it in a negative way.
You are getting the warning because all fields in a class extending StatelessWidget should be final.
Fix the warning by adding the final keyword before the type declaration like below:
final String myVar;
From the documentations.
StatelessWidget class. A widget that does not require mutable state.
https://docs.flutter.io/flutter/widgets/StatelessWidget-class.html
I hope this answers your question
The point of changing variable's value in a stateful widget is that you can call
setState(() {
myVar = 'clicked';
});
Which would rebuild the UI, changing a Text widget's content.
Try adding a Text(myVar) to your column, in a stateless widget it wouldn't change on a press of a button. But in a stateful widget it will change.
If you need to change the state of a variable in a Widget, you need to use a StetefullWidget.
class MyWidget extends StatefulWidget {
final String myInitialVar;
const MyWidget({Key key, this.myInitialVar}) : super(key: key);
#override
State<StatefulWidget> createState() => MyWidgetState(myInitialVar);
}
class MyWidgetState extends State<MyWidget> {
String myVar;
MyWidgetState(this.myVar);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
MaterialButton(
child: Text('Click me do change variable'),
onPressed: () {
setState(() {
myVar = 'Clicked!';
});
},
),
MaterialButton(
child: Text('Click me to print the variable'),
onPressed: () {
print(myVar);
},
),
],
),
);
}
}
so this is a widget in my main screen. KeypadButton is imported from KeypadButton.dart
KeypadButton(
number: 4,
userAnswer: _userAnswer,
),
this is keypadbutton.dart
import 'package:flutter/material.dart';
class KeypadButton extends StatefulWidget {
KeypadButton({this.number, this.userAnswer});
The this.number is 4 and userAnswer is _userAnswer (they are both from main screen)
final int number;
String userAnswer;
#override
_KeypadButtonState createState() => _KeypadButtonState();
}
class _KeypadButtonState extends State<KeypadButton> {
#override
Widget build(BuildContext context) {
return Container(
child: FlatButton(
child: Text(
widget.number.toString(),
style: TextStyle(
color: Colors.white,
),
),
onPressed: () => setState(() {
widget.userAnswer += widget.number.toString();
}),
),
);
}
}
You can't change your props directly inside State Part of your Widget. So Widget can depend on external props and can't change them if you pass a property as a variable.
So one of the approaches is using callback as property for your widget, and call it inside this widget when you want. This callback needs to change the state of your main widget that uses KeypadButton.
Or you can use a controller like in standard TextEdit widget from the Flutter SDK. For example, you can use some model class that will keep some information, in KeypadButton you change this model via API of this model class. And in the main widget, you need to get this info from model class