i would like to know o can i change the value of a child widget in flutter if a certain condition is met, for example the color of an icon in the trailing
Here is some pseudo-code:
if(condition){
trailing Icon(Icons.favorite).color = Colors.red[500]
}else{
trailing = Icon(Icons.Favorite).color = Colors.blue[300]
}
Thank you.
you wanna something like this?
if yes, try this code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
bool colorIndex = true;
void _changeColor(val) {
setState(() {
this.colorIndex = val;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_changeColor(!colorIndex);
},
child: Icon(Icons.touch_app),
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(50.0),
child: Card(
child: ListTile(
title: Text('Click FAB to change color'),
trailing: Icon(
Icons.favorite,
color: colorIndex ? Colors.red[500] : Colors.blue[300],
),
),
),
),
),
),
);
}
}
You can change anything under any condition you define. The most simple example is using setState to update a value that can be inspected during build. This value could change under any condition you like. Calling setState will trigger the UI to rebuild (calls the build method).
Here is a Widget. It displays the text "Hello, World!" in the center of the screen. The AppBar at the top has a leading IconButton Widget. When the IconButton is pressed, it will toggle the color of the "Hello, World!" text. It does this by updating the state of Widget and toggling the value of the blue variable. The condition is: if (blue) {} or "if blue is equal to true then change the color." During the build of the UI, the code inspects the value of blue and determines what TextStyle to apply to the "Hello, World!" text.
import 'package:flutter/material.dart';
class ColorChangeWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _ColorChangeWidgetState();
}
class _ColorChangeWidgetState extends State<ColorChangeWidget> {
bool blue = false;
#override
Widget build(BuildContext context) {
TextStyle style = TextStyle(color: Colors.black);
if (blue) {
style = TextStyle(color: Colors.blue);
}
return Scaffold(
appBar: AppBar(
title: Text("Test"),
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
blue = !blue;
});
},
),
),
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(8.0),
child: Text("Hello, World!", style: style)
)
);
}
}
Related
I have two widgets in a column. One is Text and second is TextButton. What i want that if i click on button then the Text widget rebuild only not the whole page.
I am new to flutter how can i achieve this? If i convert this to a statful widget and call setState method then whole page will be rebuild. but i want to know any trick to do rebuild only a single widget out of whole page.
class Page3 extends StatelessWidget {
Color color = Colors.red;
changeColor() {
// do something to rebuild only 1st column Text not the whole page
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
Text(
'Title',
style: TextStyle(color: color),
),
//Second widget
TextButton(
onPressed: () => changeColor(),
child: Text('change color of title'),
)
],
));
}
}
Please refer to below code
ValueListenableBuilder widget. It is an amazing widget. It builds the widget every time the valueListenable value changes. Its values remain synced with there listeners i.e. whenever the values change the ValueListenable listen to it. It updates the UI without using setState() or any other state management technique.
In Dart, a ValueNotifier is a special type of class that extends a ChangeNotifer . ... It can be an int , a String , a bool or your own data type. Using a ValueNotifier improves the performance of Flutter app as it can help to reduce the number times a widget gets rebuilt.
ValueListenableBuilder will listen for changes to a value notifier and automatically rebuild its children when the value changes.
For more info refer to this link description
Solution 1
class Page3 extends StatelessWidget {
Color color = Colors.red;
final ValueNotifier<bool> updateColor = ValueNotifier(false);
changeColor(Color changedColor) {
// do something to rebuild only 1st column Text not the whole page
color = changedColor;
updateColor.value = !updateColor.value;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
ValueListenableBuilder<bool>(
valueListenable: updateColor,
builder: (context, val, child) {
return Text(
'Title',
style: TextStyle(color: color),
);
}),
//Second widget
TextButton(
onPressed: () => changeColor(Colors.purple),
child: Text('change color of title'),
)
],
));
}
}
Solution 2
In ValueListenable we pass our created ValueNotifier variable whose changes will be notified and in builder we will return a widget that will be reflected every time when the value of ValueNotifier will be changed.
class Page3 extends StatelessWidget {
// Color color = Colors.red;
final ValueNotifier<Color> updateColor = ValueNotifier(Colors.red);
changeColor(Color changedColor) {
// do something to rebuild only 1st column Text not the whole page
updateColor.value = changedColor;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
ValueListenableBuilder<Color>(
valueListenable: updateColor,
builder: (context, val, child) {
return Text(
'Title',
style: TextStyle(color: val),
);
}),
//Second widget
TextButton(
onPressed: () => changeColor(Colors.purple),
child: Text('change color of title'),
)
],
));
}
}
Here's the code of what you need to do
class Demo extends StatefulWidget {
const Demo({Key? key}) : super(key: key);
#override
State<Demo> createState() => _DemoState();
}
class _DemoState extends State<Demo> {
var isTextChanged = false;
Void changeColor() {
setState(() {
isTextChanged = true;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page3'),
),
body: Column(
children: [
//First widget
Text(
'Title',
style: TextStyle(color: isTextChanged ? Colors.red : Colors.black),
),
//Second widget
TextButton(
onPressed: () => changeColor(),
child: Text('change color of title'),
)
],
));
}
}
setStatefunction can not be called inside StatelessWidget widget. if you want to rebuild the widget tree, you have to convert it to StatefulWidget.
This is what you can do.
class Page3 extends StatefulWidget {
const Page3();
#override
_Page3State createState() => _Page3State();
}
class _Page3State extends State<Page3> {
Color color = Colors.red;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
Text(
'Title',
style: TextStyle(color: color),
),
TextButton(
onPressed: () => changeColor(),
child: Text('change color of title'),
)
]),
);
}
changeColor() {
setState(() {
color = Colors.green;
});
}
}
If you want to rebuild the Text widget without rebuilding the whole Page3 then you need to got for 'state management' solution.
Try below code hope its help to you. you must used StateFulWidget for that
Create one bool variable
bool isButtonPressed = true;
Your widgets:
Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Title',
style: isButtonPressed
? TextStyle(
color: Colors.black,
fontSize: 20,
)
: TextStyle(
color: Colors.green,
fontSize: 20,
),
),
),
TextButton(
child: new Text('Change color'),
onPressed: () {
setState(() {
isButtonPressed = !isButtonPressed;
});
},
),
],
),
Your Screen without button pressed:
Your Screen with button pressed:
You need to understand how setState works.
Lets assume you have a class named HomeScreen, within the homescreen you are overriding the build method to build your own widgets.
Widget build(BuildContext context){
return Column(
children:<Widget> [
FirstTextWidget();
SecondTextWidget();
ThirdTextWidget(),
])
}
when you call SetState function within that "homesceeen" class, the homescreen class itself calls the build method again and all of componenets you have returned within build function get re-rendered. Every text within homescreen class gets rerendered.
So whats the solution?
The Solution is separate your stateful widget with different class so that only those widgets gets rerendered when needed not whole. I will prefer you to use State Management plugin like Provider, bloc etc.
I am new to flutter. I have taken inspiration from this app https://play.google.com/store/apps/details?id=com.nikitadev.usconstitution&hl=en and I am implementing the fontsize adjustment dialogbox with flutter. I am really stuck.
Make static variable and use the value in your default theme. When font size is increased set the value of that variable to this font size.
//Initialize a variable at the top to change
double _textDefaultSize = 16;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
textTheme: TextTheme(
bodyText1: TextStyle(
fontSize: _textDefaultSize,
//Use the text Size in the main theme
),
),
),
home: Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
title: Text("TextColor checking"),
),
body: Center(
child: Column(
children: <Widget>[
Text(
"Example Text",
style: TextStyle(fontSize: _textDefaultSize),
//Use the font size in all texts
),
FlatButton(
onPressed: () {
setState() {
_textDefaultSize++; //Change the value of variable here
}
},
child: Text("Increase Size"),
),
FlatButton(
onPressed: () {
setState() {
_textDefaultSize--; //Change the value of variable here
}
},
child: Text("Increase Size"),
),
],
),
),
),
);
}
}
```
I am trying to do this kind of thing with Flutter :
https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F0B3T7oTWa3HiFcHBDaTlreHdVZGc%2Fitem-selection-selecting-items.mp4
var gestureTemp = GestureDetector(
onLongPress: (){
print('LONG PRESSED');
//CHANGE APPBAR
},
child: Padding(
padding: EdgeInsets.only(right:8),
child: Chip(
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: icon
),
label: Text(space.label, style: TextStyle(fontSize: 12, color:Colors.grey.shade800))
),
));
It detects the long press, but I don't know how to change my appbar...
Any ideas ?
EDIT: Here is what I do
var appBar1 = AppBar(...);
var appBar2 = AppBar(...);
var appBar = appBar1;
My appBar is displayed in my Scaffold.
On my GestureDetector :
onLongPress: (){
print('LONG PRESSED');
setState(() {
appBar = appBar2;
});
},
Welcome to StackOverflow!
The approach you described sounds quite right. Here is a standalone example so you can double check your code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: MyPage());
}
}
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
static final AppBar _defaultBar = AppBar(
title: Text('Inbox'),
leading: Icon(Icons.menu),
actions: <Widget>[Icon(Icons.search), Icon(Icons.more_vert)],
backgroundColor: Colors.black,
);
static final AppBar _selectBar = AppBar(
title: Text('1'),
leading: Icon(Icons.close),
actions: <Widget>[
Icon(Icons.flag),
Icon(Icons.delete),
Icon(Icons.more_vert)
],
backgroundColor: Colors.deepPurple,
);
AppBar _appBar = _defaultBar;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: _appBar,
body: Center(
child: RaisedButton(
child: Text('Switch!'),
onPressed: () {
setState(() {
_appBar = _appBar == _defaultBar
? _selectBar
: _defaultBar;
});
},
),
),
);
}
}
I've searched high and low, but cannot find a way to change the background color on a ListTile, for example when it is tapped by the user.
Does anyone have a solution to what seems like a common use case?
To change the background color of a ListTile, you can simply wrap it in a Container and change its color attribute. Afterwards you can change the color, when onTap of the ListTile is triggered.
Demo:
Demo Source:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: CustomTile()
),
),
);
}
}
class CustomTile extends StatefulWidget {
#override
CustomTileState createState() => CustomTileState();
}
class CustomTileState extends State<CustomTile> {
Color color;
#override
void initState() {
super.initState();
color = Colors.transparent;
}
#override
Widget build(BuildContext context) {
return Container(
color: color,
child: ListTile(
title: Text('Title'),
subtitle: Text('Subtitle'),
onTap: () {
setState(() {
color = Colors.lightBlueAccent;
});
},
),
);
}
}
As You Haven't Describes your Use Case or shared any Code i have shared sample code that Change Listile Color onTap()
class Screen1 extends StatefulWidget {
#override
Screen1State createState() {
return new Screen1State();
}
}
class Screen1State extends State<Screen1> {
bool _color;
#override
void initState() {
super.initState();
_color = true;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Card(
color: _color ? Colors.deepOrangeAccent : Colors.purpleAccent,
child: ListTile(
onTap: () {
setState(() {
_color = !_color;
});
},
title: Text(
'Title',
style: TextStyle(color: Colors.white),
),
subtitle: Text(
'Subtitle',
style: TextStyle(color: Colors.white),
),
),
),
));
}
}
If you just want a quick way to do it, without much code and customization, you can wrap it with RaisedButton like this :
RaisedButton(
color: ...
child: ListTile(
color: Colors.transparent,
...
)
)
You can also use many properties like elevation, highlight color, focus color and much more.
How do you update the state of a sibling widget in Flutter?
For example, if I have a rectangle widget, I can change its color from within the widget by calling setState() and changing the color variable (as the "Turn Green" button does below). But, say I wanted a button outside of the rectangle that would change its color. How do I communicate to the Rectangle that it's time to change its color, and what color to change to?
Here is my sample code. When the user presses the "Turn Blue" button, I'd like the rectangle to turn blue, but I don't have access to its state from the sibling widget.
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Hello Rectangle',
home: Scaffold(
appBar: AppBar(
title: Text('Hello Rectangle'),
),
body: Column(
children: <Widget>[
HelloRectangle(),
FlatButton(
child: Text('Turn Blue!',
style: TextStyle(fontSize: 40.0),
textAlign: TextAlign.center,
),
onPressed: () {
// How to update state of the Rectangle from here?
},
),
]
),
),
),
);
}
class HelloRectangle extends StatefulWidget {
#override
HelloRectangleState createState() {
return new HelloRectangleState();
}
}
class HelloRectangleState extends State<HelloRectangle> {
Color _color;
#override
void initState() {
super.initState();
_color = Colors.red;
}
#override
Widget build(BuildContext context) {
return Center(
child: Container(
color: _color,
height: 400.0,
width: 300.0,
child: Center(
child: FlatButton(
child: Text('Turn Green!',
style: TextStyle(fontSize: 40.0),
textAlign: TextAlign.center,
),
onPressed: () {
// I can update the state from here because I'm inside the widget
setState(() {
_color = Colors.green;
});
},
),
),
),
);
}
}
The rule of thumb is that you can't access the state of any Widget that isn't above you in the hierarchy. So, basically we need to move the state (color) up to an ancestor. Introduce a StatefulWidget that builds the Scaffold or Column and store the rectangle color there. Now the rectangle widget no longer needs to store the color, so can become a stateless widget - and you can pass the color in through the constructor. Both onPressed callbacks can now call a method on the new StatefulWidget which calls setState. (You could pass that method down to the rectangle widget, amongst other ways.)
There are two good introductions to best practise here and here.
Here is basic example how to do it from outside.
import 'package:flutter/material.dart';
void main() {
runApp(
new MyApp(),
);
}
class MyApp extends StatefulWidget {
const MyApp({
Key key,
}) : super(key: key);
#override
MyAppState createState() {
return new MyAppState();
}
}
class MyAppState extends State<MyApp> {
MaterialColor _color = Colors.green;
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Hello Rectangle',
home: Scaffold(
appBar: AppBar(
title: Text('Hello Rectangle'),
),
body: Column(children: <Widget>[
HelloRectangle(_color),
FlatButton(
child: Text(
_color == Colors.green ? "Turn Blue" : "Turn Green",
style: TextStyle(fontSize: 40.0),
textAlign: TextAlign.center,
),
onPressed: () {
setState(() {
_color = _color == Colors.green ? Colors.blue : Colors.green;
});
},
),
]),
),
);
}
}
class HelloRectangle extends StatefulWidget {
final Color color;
HelloRectangle(this.color);
#override
HelloRectangleState createState() {
return new HelloRectangleState();
}
}
class HelloRectangleState extends State<HelloRectangle> {
HelloRectangleState();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: Container(
color: widget.color,
height: 400.0,
width: 300.0,
),
);
}
}