How to change the text color which is in a different widget on switch with a flutter provider? - flutter

How to change the text color which is in a different widget on switch with a flutter provider?
When switch is on change text color to red else change to green. Bu don't merge first and second widgets.
When clicked switch button change other widget's text.
`
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(const SwitchApp());
class SwitchApp extends StatelessWidget {
const SwitchApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Switch Sample')),
body: const Center(
child: SwitchExample(),
),
),
);
}
}
class SwitchExample extends StatefulWidget {
const SwitchExample({super.key});
#override
State<SwitchExample> createState() => _SwitchExampleState();
}
class _SwitchExampleState extends State<SwitchExample> {
bool light = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Switch(
// This bool value toggles the switch.
value: light,
activeColor: Colors.red,
onChanged: (bool value) {
// This is called when the user toggles the switch.
setState(() {
light = value;
});
},
),
MyText()
],
);
}
}
class MyText extends StatelessWidget {
const MyText({super.key});
#override
Widget build(BuildContext context) {
return const Text('Change my color',
style: TextStyle(color: Colors.green));
}
}
`

The easiest way would be to pass the color down into the constructor of MyText widget, since MyText widget is being built as a child of SwitchExample which is handling the switch state.
import 'package:provider/provider.dart';
void main() => runApp(const SwitchApp());
class SwitchApp extends StatelessWidget {
const SwitchApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Switch Sample')),
body: const Center(
child: SwitchExample(),
),
),
);
}
}
class SwitchExample extends StatefulWidget {
const SwitchExample({super.key});
#override
State<SwitchExample> createState() => _SwitchExampleState();
}
class _SwitchExampleState extends State<SwitchExample> {
bool light = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Switch(
// This bool value toggles the switch.
value: light,
activeColor: Colors.red,
onChanged: (bool value) {
// This is called when the user toggles the switch.
setState(() {
light = value;
});
},
),
MyText(light ? Colors.green : Colors.blue)
],
);
}
}
class MyText extends StatelessWidget {
final Color color;
const MyText(this.color, {super.key});
#override
Widget build(BuildContext context) {
return Text('Change my color',
style: TextStyle(color: color));
}
}
But, if you wanted to use provider so that MyText could be a child widget anywhere below the provider widget in the tree you could use Provider with a ChangeNotifier:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(const SwitchApp());
class ColorModel extends ChangeNotifier {
Color color = Colors.green;
void setColor(Color color) {
this.color = color;
notifyListeners();
}
}
class SwitchApp extends StatelessWidget {
const SwitchApp({super.key});
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ColorModel>(
create: (context) => ColorModel(),
child: MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('Switch Sample')),
body: const Center(
child: SwitchExample(),
),
),
),
);
}
}
class SwitchExample extends StatefulWidget {
const SwitchExample({super.key});
#override
State<SwitchExample> createState() => _SwitchExampleState();
}
class _SwitchExampleState extends State<SwitchExample> {
bool light = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Switch(
// This bool value toggles the switch.
value: light,
activeColor: Colors.red,
onChanged: (bool value) {
// This is called when the user toggles the switch.
setState(() {
light = value;
});
Provider.of<ColorModel>(context, listen: false)
.setColor(value ? Colors.green : Colors.blue);
},
),
MyText()
],
);
}
}
class MyText extends StatelessWidget {
const MyText({super.key});
#override
Widget build(BuildContext context) {
return Consumer<ColorModel>(builder: (context, state, _) {
return Text('Change my color', style: TextStyle(color: state.color));
});
}
}
Check out flutter's docs for more info: https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple

Related

how to disable button in Flutter 3.3.4

in Flutter 3.3.4 , I want control the state of the button by passing an object with its properties
. I tried some solutions in stackoverflow (e.g How do I disable a Button in Flutter? ),but failed。
I print the flag of the object , it looks right.
here is my code
// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
SwitchWidget wifiSwitch = SwitchWidget();
// SwitchWidget timeSwitch = SwitchWidget();
// SwitchWidget locationSwitch = SwitchWidget();
return MaterialApp(
title: 'Startup N1ame Generator',
home: Scaffold(
appBar: AppBar(
title: const Text('Startup Name Generator'),
),
body: Center(
child: Row(
children: [
Column(children: [wifiSwitch]),
Column(children: [ButtonWidget(wifiSwitch)])
],
),
),
),
);
}
}
class SwitchWidget extends StatefulWidget {
bool flag = true;
SwitchWidget({Key? key}) : super(key: key);
#override
State<SwitchWidget> createState() => _SwitchWidgetState(this);
}
class _SwitchWidgetState extends State<SwitchWidget> {
SwitchWidget switchWidget;
_SwitchWidgetState(this.switchWidget);
#override
Widget build(BuildContext context) {
return Container(
child: Switch(
value: switchWidget.flag,
onChanged: (newValue) => {
setState(() {
switchWidget.flag = newValue;
print("-----------${switchWidget.flag}");
})
},
),
);
}
}
class ButtonWidget extends StatefulWidget {
late SwitchWidget _switchWidget;
SwitchWidget get switchWidget => _switchWidget;
set switchWidget(SwitchWidget switchWidget) => {
print('The ButtonWidget is $switchWidget.'),
_switchWidget = switchWidget
};
ButtonWidget(switchWidget, {Key? key}) : super(key: key) {
this.switchWidget = switchWidget;
}
#override
State<ButtonWidget> createState() => _ButtonWidgetState(switchWidget);
}
class _ButtonWidgetState extends State<ButtonWidget> {
SwitchWidget switchWidget;
_ButtonWidgetState(this.switchWidget);
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(50, 1, 1, 1),
child: ElevatedButton(
// color: Colors.blue,
// disabledColor: Colors.grey,
// textColor: Colors.black,
child: Text("123"),
// onPressed: () {},
onPressed: this.switchWidget.flag ? _incrementCounter : null,
style: ButtonStyle(
foregroundColor: MaterialStateProperty.resolveWith(
(states) {
if (states.contains(MaterialState.disabled)) {
return Colors.grey;
} else {
return Colors.white;
}
},
),
)),
);
{}
}
void _incrementCounter() {
print("object******** ${this.switchWidget.flag}");
}
}
Why do you pass a reference of SwitchWidget to _SwitchWidgetState? You should move the property bool flag = true; to _SwitchWidgetState and then change it directly in setState(() => flag = newValue);.
Also, your ButtonWidget is not rebuilt on change in SwitchWidget. You'll have to use some sort of state management in order to disable the button on a state change of your switch widget.
For example using callbacks:
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_svg/flutter_svg.dart';
class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});
#override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
bool _isDisabled = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
SwitchWidget(initialValue: true, onChanged: (val) => setState(() => _isDisabled = val)),
ButtonWidget(isDisabled: _isDisabled),
],
);
}
}
class SwitchWidget extends StatefulWidget {
final bool initialValue;
final void Function(bool) onChanged;
const SwitchWidget({super.key, required this.onChanged, required this.initialValue});
#override
State<SwitchWidget> createState() => _SwitchWidgetState();
}
class _SwitchWidgetState extends State<SwitchWidget> {
late bool _value;
#override
void initState() {
super.initState();
_value = widget.initialValue;
}
#override
Widget build(BuildContext context) {
return Switch(
value: _value,
onChanged: (val) {
setState(() => _value = val);
widget.onChanged(val);
},
);
}
}
class ButtonWidget extends StatelessWidget {
final bool isDisabled;
const ButtonWidget({super.key, required this.isDisabled});
#override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: isDisabled
? null
: () {
//Some logic
},
child: Text("Press me!"),
);
}
}
You can pass null where you place your function, or even some of Flutter's Widgets already have the enabled property. But setState and change the function to null and you should get what you want.

Flutter - How to trigger an animation inside a child widget from its parent widget [duplicate]

Let said I have a widget "mySonWidget" inside this widget I have a function "updateIconColor", I want to call that function from the father of "mySonWidget"
I did something similiar with callback but this is not the same scenario.
I saw people other widgets doing similar thing with controllers, but I don't know how create a custom controller.
How can I do it?
HELP
class mySonWidget extends StatefulWidget {
#override
_mySonWidgetState createState() => _mySonWidgetState();
}
class _mySonWidgetState extends State<mySonWidget> {
var _iconColor = Colors.red[500];
void updateIconColor() {
setState(() {
print('updateIconColor was called');
_iconColor = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (Icon(Icons.star)),
color: _iconColor,
onPressed: () {},
),
);
}
}
father example:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(children: <Widget>[
mySonWidget(),
FlatButton(
onPressed: () {
/*..Call Function inside mySonWidget (updateIconColor) ..*/
},
child: Text(
"Change Color",
),
),
]),
),
);
}
}
You can copy paste run full code below
You can use GlobalKey can use _key.currentState to call updateIconColor()
code snippet
GlobalKey _key = GlobalKey();
...
mySonWidget(key: _key),
FlatButton(
onPressed: () {
final _mySonWidgetState _state = _key.currentState;
_state.updateIconColor();
},
...
class mySonWidget extends StatefulWidget {
mySonWidget({Key key}) : super(key: key);
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
GlobalKey _key = GlobalKey();
#override
Widget build(BuildContext context) {
return MaterialApp(
//theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
body: Column(children: <Widget>[
mySonWidget(key: _key),
FlatButton(
onPressed: () {
final _mySonWidgetState _state = _key.currentState;
_state.updateIconColor();
},
child: Text(
"Change Color",
),
),
]),
),
),
);
}
}
class mySonWidget extends StatefulWidget {
mySonWidget({Key key}) : super(key: key);
#override
_mySonWidgetState createState() => _mySonWidgetState();
}
class _mySonWidgetState extends State<mySonWidget> {
var _iconColor = Colors.red[500];
void updateIconColor() {
setState(() {
print('updateIconColor was called');
_iconColor = Colors.green;
});
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (Icon(Icons.star)),
color: _iconColor,
onPressed: () {},
),
);
}
}

Hover Color for Icon

I am trying to implement a favorite Button in Flutter. I am happy with the properties when clicking the button but I am not happy with the hover animation.
I want that only the icon color changes on a hover. I don't like the Bubble around the IconButton. Here is my approach:
MouseRegion FavoriteButton(int index) {
bool _favoriteHover = false;
return MouseRegion(
onHover: (e) {
setState(() {
_favoriteHover = true;
});
},
child: IconButton(
icon: Icon(
_projects[index].favorite
? Icons.favorite
: Icons.favorite_border_outlined,
color: _favoriteHover ? Colors.yellow : Colors.white,
),
onPressed: () {
setState(() {
_projects[index].favorite
? _projects[index].favorite = false
: _projects[index].favorite = true;
// TODO: Save Favorite state to config
});
},
color: Colors.transparent,
),
);
Unfortunately, the icon color does not change on hover.
Someone can help?
You try:
Don't hover: https://i.stack.imgur.com/oxGUh.png
Hover:https://i.stack.imgur.com/UyW2j.png
/// Flutter code sample for MouseRegion
// This example makes a [Container] react to being entered by a mouse
// pointer, showing a count of the number of entries and exits.
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatefulWidget(),
),
),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool _favorite = false;
void _incrementEnter(PointerEvent details) {
setState(() {
_favorite = true;
});
}
void _incrementExit(PointerEvent details) {
setState(() {
_favorite = false;
});
}
Icon setIcon(){
if(_favorite){
return Icon(Icons.favorite);
}
return Icon(Icons.favorite_border_outlined);
}
Color setColor(){
if(_favorite){
return Colors.yellow;
}
return Colors.black;
}
#override
Widget build(BuildContext context) {
return Container(
child: MouseRegion(
onEnter: _incrementEnter,
onExit: _incrementExit,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: setIcon(),
color: setColor(),
onPressed: (){},
),
],
),
),
),
);
}
}
[1]: https://i.stack.imgur.com/UyW2j.png

I am using notifyListner from flutter Provider package but my UI is not updating

I am using notifyListner from flutter Provider package but my UI is not updating whenever I am typing the letters in the TextField. I am making this app just to understand how Provider works. My appbar and text is supposed to change whenever I type the text in TextFiled. Here's my code,
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider<Data>(
create: (context) => Data(),
child: MaterialApp(
home: Scaffold(
appBar: AppBar(
title: MyAppBar(),
),
body: SafeArea(
child: Column(
children: [
MyTextField(),
Expanded(
child: MyTextWidget(),
),
],
),
),
),
),
);
}
}
class MyTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
onChanged: (newValue) {
Provider.of<Data>(context, listen: true).changeString(newValue);
},
),
);
}
}
class MyTextWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Text(Provider.of<Data>(context, listen: true).appName),
);
}
}
class MyAppBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Text(Provider.of<Data>(context, listen: true).appName);
}
}
class Data extends ChangeNotifier {
String appName = 'Understanding Provider';
void changeString(String newString) {
appName = newString;
notifyListeners();
}
}
Please somebody help, Thanks!
You should not listen to your provider when you update it inside MyTextField:
class MyTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
onChanged: (newValue) {
Provider.of<Data>(context, listen: false).changeString(newValue);
},
),
);
}
}
Set listen: false.

Provider does not update Text widget

I have a problem with updating text widget in Level3 class after input some text in textField widget.
Appreciate your help
Expose data in below code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// home: TasksScreen(),
home: ChangeNotifierProvider<Data>(
create: (context) => Data(),
child: Scaffold(
appBar: AppBar(
title: Container(
child: MyText(),
),
),
body: Level1(),
),
),
);
}
}
create Data class for model data in below class
class Data extends ChangeNotifier {
String data = 'this data';
void changeString(String newString) {
data = newString;
print(newString);//don't print anything after typing in textFild
print(data);//don't print either
notifyListeners();
}
}
I want to use Data object properties in MyTextField in below code
but it seems do not trigger Provider.of<Data>(context).changeString(newValue)
class MyTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TextField(
onChanged: (newValue) {
print(newValue);//print newValue correctly
Provider.of<Data>(context).changeString(newValue);
},
);
}
}
class Level3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(
//this part don't update as typing in textField
Provider.of<Data>(context).data,
//will return an instance of Provider
//type found in the context that is sent as a parameter
),
),
);
}
}
You can copy paste run full code below
In onChanged, You can use listen: false
code snippet
return TextField(
onChanged: (newValue) {
print(newValue); //print newValue correctly
Provider.of<Data>(context, listen: false).changeString(newValue);
},
);
working demo
full code
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Data extends ChangeNotifier {
String data = 'this data';
void changeString(String newString) {
data = newString;
print(newString); //don't print anything after typing in textFild
print(data); //don't print either
notifyListeners();
}
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// home: TasksScreen(),
home: ChangeNotifierProvider<Data>(
create: (context) => Data(),
child: Scaffold(
appBar: AppBar(
title: Container(
child: MyTextField(),
),
),
body: Level3(),
),
),
);
}
}
class MyTextField extends StatelessWidget {
#override
Widget build(BuildContext context) {
return TextField(
onChanged: (newValue) {
print(newValue); //print newValue correctly
Provider.of<Data>(context, listen: false).changeString(newValue);
},
);
}
}
class Level3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(
//this part don't update as typing in textField
Provider.of<Data>(context).data,
//will return an instance of Provider
//type found in the context that is sent as a parameter
),
),
);
}
}
void main() {
runApp(MyApp());
}
You can try this
(context.watch<Data>().data).toString();