quantity increase decrease display counter field - flutter

New to flutter and tried several solutions I cannot get working for simple item counter
Example icons on row. 0 should increase decrease as i press icon +1 or -1
Donut +1 0 -1
When I press plus_one icon button +1 it updates the print terminal so I know button is working. if I hot refresh the phone emulator the counter and display icon on phone updates to correct count.
How do I tell TextBox to update state ( show updated count on screen) when counter has been increased by OnPress in IconBoxState?
'''
class _IconBoxState extends State<StatefulWidget> {
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Material(
color: Colors.white,
child: Center(
child: Ink(
decoration: const ShapeDecoration(
color: Colors.lightBlue,
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(Icons.plus_one),
color: Colors.white,
iconSize: 25,
onPressed: () {
setState(() {
_counter += 10;
print('this is counter + $_counter');
//new TextBox(); not working....
});
},
),
),
),
),
],
);
}
}
class TextBox extends StatefulWidget {
#override
_TextBoxState createState() => _TextBoxState();
}
class _TextBoxState extends State<TextBox> {
// int _counter = 6;
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
width: 50,
height: 50,
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(),
),
);
}
}
'''

when you are setting the state with setState it only rebuilds the widget, where it is located and other widget's that the container widget contains, so in your case you have TextBox outside the IconBox, so only IconBox is rebuilt and TextBox can't detect state change so it stays same, you have many ways to solve it. 1. somehow store both of the widget inside the container widget and rebuild the state of the container widget, you can do this, 2. use provider, 3. use InheritedWidget 4. use BloC
This is a full code of version one, so you can play around, You will need to include ContainerWidget inside the page you want it to be displayed or in the Scaffold of MaterialApp:
class ContainerWidget extends StatefulWidget {
#override
_ContainerWidgetState createState() => _ContainerWidgetState();
}
class _ContainerWidgetState extends State<ContainerWidget> {
int counter = 0;
void increase() {
counter += 1;
}
void decrease() {
counter -= 1;
}
#override
void setState(fn) {
super.setState(fn);
}
stateSetter(String event) {
if (event == "increase") {
increase();
setState(() {});
} else if (event == "decrease") {
decrease();
setState(() {});
}
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
TextBox(
counter: counter,
),
IconBox(
containerSetState: stateSetter,
),
],
),
);
}
}
class IconBox extends StatefulWidget {
final Function containerSetState;
IconBox({this.containerSetState});
#override
_IconBoxState createState() => _IconBoxState();
}
class _IconBoxState extends State<IconBox> {
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Material(
color: Colors.white,
child: Center(
child: Ink(
decoration: const ShapeDecoration(
color: Colors.lightBlue,
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(Icons.plus_one),
color: Colors.white,
iconSize: 25,
onPressed: () {
setState(() {
widget.containerSetState("increase");
//new TextBox(); not working....
});
},
),
),
),
),
Material(
color: Colors.white,
child: Center(
child: Ink(
decoration: const ShapeDecoration(
color: Colors.lightBlue,
shape: CircleBorder(),
),
child: IconButton(
icon: Icon(Icons.exposure_minus_1),
color: Colors.white,
iconSize: 25,
onPressed: () {
setState(() {
widget.containerSetState("decrease");
//new TextBox(); not working....
});
},
),
),
),
),
],
);
}
}
class TextBox extends StatefulWidget {
final int counter;
TextBox({this.counter});
#override
_TextBoxState createState() => _TextBoxState();
}

Related

Dart Function not inputting Variables

I'm creating a Dart Function to use repeatedly across my app. its 2 buttons linked to a counter locally (localCounter, it's between the 2 buttons) as well as linked to a counter that catches all the button presses across the app (GlobalCuonter) when I input the the integers directly into the code, it works fine but when I use the it as a function, and make it so i can input the variables, it doesn't seem to work but i'm also not getting any errors in the code.
import 'package:flutter/material.dart';
void main() {
runApp(
const MyApp(),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
child: MainPage(),
),
),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);
#override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int TP1LeftCounter = 0; //localCounter
int movpLeftCounter = 0; //globalCounter
Row TpScores(int localCounter, int globalCounter) { //Dart Function I'm trying to create
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: InkWell(
onTap: () {
setState(() {
if (localCounter > 0) localCounter--;
if (globalCounter > 0) globalCounter--;
});
},
child: Container(
child: Icon(Icons.remove, color: Colors.white),
width: 25.0,
height: 35.0,
color: Colors.blueGrey[900],
),
),
),
Container(
child: Text(
'$localCounter',
style: TextStyle(
fontFamily: 'SourceSansPro',
fontSize: 40.0,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: InkWell(
onTap: () {
setState(() {
if (localCounter < 12) localCounter++;
if (globalCounter < 12) globalCounter++;
});
},
child: Container(
child: Icon(Icons.add, color: Colors.white),
width: 25.0,
height: 35.0,
color: Colors.blueGrey[900],
),
),
),
],
);
}
A
nd then in my build i put:
Expanded(
child: Container(
height: 50.0,
child: TpScores(TP1LeftCounter, movpLeftCounter),
),
),
the counters don't tick up or down but the buttons are working.
am I missing something? cheers
It's because the value is copied, you're not incrementing TP1LeftCounter and movpLeftCounter but localCounter and globalCounter
You should increment TP1LeftCounter, movpLeftCounter in the setState method.
Example
void main() {
var v1 = 0;
void incr(int value) {
value++;
print('value is $value');
print('v1 is $v1');
}
incr(v1);
}
Will output
value is 1
v1 is 0

Flutter onPressed trigger State of another widget

I need help with flutter build management. My Goal is to rebuild my side navigation bar with the SmallSideMenu() or the opposite SideMenu().
Do you have an idea how I can trigger the Build process of my LargeView widget, so that it's rebuilt with the correspondent SideMenu?
The button is defined like this:
IconButton(
onPressed: () {
checkState();
},
icon: HeroIcon(
HeroIcons.arrowNarrowRight,
size: 16.0,
),
),
The value of the sideMenuOpen variable and function is set globally;
checkState() {
if (sideMenuOpen == true) {
sideMenuOpen = false;
} else {
sideMenuOpen = true;
}
}
the SideMenu is defined here.
class LargeView extends StatefulWidget {
const LargeView({
Key? key,
}) : super(key: key);
#override
State<LargeView> createState() => _LargeViewState();
}
class _LargeViewState extends State<LargeView> {
#override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: SizedBox(
width: 100,
child: sideMenuOpen ? SideMenu() : SmallSideMenu(),
),
),
Expanded(
flex: 10,
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(20.0),
color: greyColor,
child: Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(15.0)),
child: localNavigator())),
),
)
],
);
}
}
make sideMenuOpen a state in stateful widget and use setState as
checkState() {
if (sideMenuOpen == true) {
setState((){
sideMenuOpen = false;
});
} else {
setState((){
sideMenuOpen = true;
});
}
}
if you want to keep state (open/close) of navigation bar globally for that use some state management like provider instead of using global function.
You can use ValueNotifier instead of single bool. And to update UI it can be used on ValueListenableBuilder.
final ValueNotifier<bool> sideMenuOpen = ValueNotifier(false);
And
child: SizedBox(
width: 100,
child: ValueListenableBuilder<bool>(
valueListenable: sideMenuOpen,
builder: (context, value, child) => value
? SideMenu(),
: SmallSideMenu(),
),
),
And change value like
sideMenuOpen.value = true;

How to 'setState' only to the appBar icons instead of 'notifyListeners'

I have an appBar with one icon, this icon has a number which have to be updated after I change somethings in the app. I was using notifyListeners(), but this command is cleaning a list I need so I have to update that number in appbar without notifyListeners().
I tried to call SetState but it doesn't worked.. is there a way to update only the app bar?
In provider which I include more items:
void setBadge() {
_number = number;
notifyListeners(); // this line I dropped out
}
App bar Icon widget:
class AppBarWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
child: IconButton(
icon: Icon(Icons.shopping_bag_outlined),
onPressed: () async {
Navigator.of(context).pushNamed(ROUTE_CART);
},
),
builder: (_, cart, child) {
return BagBadge(
child: child,
value: cart.isEmpty ? '' : cart.number.toString(),
);
},
);
}
}
BagBadge:
class BagBadge extends StatelessWidget {
final Widget child;
final String value;
BagBadge({
#required this.child,
#required this.value,
});
#override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: <Widget>[
child,
if (value != '')
Positioned(
right: value.length < 4 ? 20 : 10,
top: 30,
child: Container(
padding: EdgeInsets.all(value.length < 4 ? 2 : 3),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).accentColor
),
constraints: BoxConstraints(
minHeight: 16,
minWidth: 16,
),
child: Text(
value,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
)
],
);
}
}
Edit: this would work only if you use a stateful widget. With stateless widget the change won't be shown.
You can try something like this:
import 'package:flutter/material.dart';
class AppBarWidget extends StatefulWidget {
#override
_AppBarWidgetState createState() => _AppBarWidgetState();
}
class _AppBarWidgetState extends State<AppBarWidget> {
int _appBarValue = 0;
#override
Widget build(BuildContext context) {
return Consumer<Cart>(
child: IconButton(
icon: Icon(Icons.shopping_bag_outlined),
onPressed: () async {
Navigator.of(context).pushNamed(ROUTE_CART);
},
),
builder: (_, cart, child) {
return BagBadge(
child: child,
value: _appBarValue == 0 ? '' : '$appBarValue',
);
},
);
}
}
setAppBarValue(int value) {
setState(() { _appBarValue = value; });
}
}
Whenever you want to change the value, just call the setAppBarValue() function.

How to disable the tooltip dynamically in flutter? [duplicate]

This question already has answers here:
how to disable tooltip dynamcically in flutter?
(4 answers)
Closed 2 years ago.
I can disable the tooltip statically.
But I want to disable tooltip dynamically when i click flatbutton.But Couldnt disable dynamically and i have no idea to do that.
If I give statically false. it works fine.
For example : If add child like TopToolbar(showTooltip : false),it works fine,
But If i give toolbar.showTooltip = false in Flatbutton onPressed method,it doesnt work.
I want to disble it in dynamically. please help me to do that.
This is my code:
import 'package:flutter/material.dart';
void main(){
runApp(MaterialApp(home: HelloWorld(),debugShowCheckedModeBanner: false,));
}
class HelloWorld extends StatefulWidget {
#override
_HelloWorldState createState() => _HelloWorldState();
}
class _HelloWorldState extends State<HelloWorld> {
bool check = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: <Widget>[
TopToolbar(),
FlatButton(
child: Text("Disable Tooltip"),
onPressed: () {
setState(() {
TopToolbar toolbar = new TopToolbar();
toolbar.showTooltip = false;
});
},
),
]),
),
));
}
}
class TopToolbar extends StatefulWidget {
bool showTooltip;
final Color backgroundColor;
final double height;
bool isVisible;
TopToolbar({
this.height = 55,
this.isVisible = true,
this.backgroundColor = const Color(0xFFEEEEEE),
Key key,this.showTooltip=true,
}) : super(key: key);
#override
_TopToolbarState createState() => _TopToolbarState();
}
class _TopToolbarState extends State<TopToolbar> {
#override
Widget build(BuildContext context) {
if (widget.isVisible) {
return Container(
foregroundDecoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.grey,
),
),
),
margin: EdgeInsets.only(bottom: 1),
color: widget.backgroundColor,
height: widget.height,
child: Stack(
children: <Widget>[
Positioned(
top: 7,
right: 60,
height: 40,
width: 40,
child: RawMaterialButton(
elevation: 0.0,
fillColor: widget.backgroundColor,
splashColor: Colors.grey[300],
child: IconButton(
icon: Icon(
Icons.bookmark,
color: Colors.grey[500],
size: 25,
),
onPressed: (){},
tooltip: widget.showTooltip ? "Bookmark" : null,
),
onPressed: (){},
),
),
],
),
);
} else {
return Container();
}
}
}
You have to store whether to show the tooltip in _HelloWorldState, not in the TopToolbar.
This would lead to doing something like this in _HelloWorldState:
class _HelloWorldState extends State<HelloWorld> {
bool showTip = true;
bool check = false;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Center(
child: Column(children: <Widget>[
TopToolbar(showTip),
FlatButton(
child: Text("Disable Tooltip"),
onPressed: () {
setState(() {
showTip = false;
});
},
),
]),
),
));
}
}
showTooltip should also be marked as final in TopToolbar class.
Your current implementation creates a new TopToolbar widget, it doesn't modify the existing widget. TopToolbar toolbar = new TopToolbar(); creates a completely different widget, just one that isn't ever mounted and shown. Therefore, toolbar.showTooltip = false; has no visible effect.
Alternatively to what I have shown you can access of the State of the TopToolbar using a GlobalKey, but I wouldn't recommend this for a beginner, it isn't necessary for your implementation at the moment, and GlobalKeys are relatively expensive.
This is too simple buddy,
make 1 global variable below main method
bool isTooltipActive = true;
Now change onPressed method like this
FlatButton(
child: Text("Disable Tooltip"),
onPressed: () {
setState(() {
if(isToolTipAvtive == false){
isToolTipAvtive = true;
}else{
isToolTipAvtive = false;
}
});
},
),
And change bookmark tooltip line like this
tooltip: isToolTipAvtive ? "Bookmark" : null,

How can I pass a custom widget into another custom widget in flutter?

I am trying to pass a custom made container (with background color, title, and onPressed properties) into another custom widget that creates a row of three of these containers. The goal is to be able to input titles for each of these buttons in the second widget like so, TriButton(title1, title2, title3). Any tips or tricks would be appreciated!
Custom container
class RectButton extends StatelessWidget {
RectButton({this.buttonChild, this.bgColor, this.onPress});
final Widget buttonChild;
final Color bgColor;
final Function onPress;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
constraints: BoxConstraints.expand(width: 100, height: 50),
child: Center(child: buttonChild),
decoration: BoxDecoration(
color: bgColor,
shape: BoxShape.rectangle,
border: Border.all(width: 1, color: Colors.white)),
padding: EdgeInsets.fromLTRB(12, 12, 12, 12),
),
);
}
}
`Tri-button code`
enum Weight {
ideal,
actual,
adjusted,
}
class TriButton extends StatefulWidget {
TriButton({this.title1, this.title2, this.title3, this.buttonChild});
final Text title1;
final Text title2;
final Text title3;
final RectButton buttonChild;
#override
_TriButtonState createState() => _TriButtonState();
}
class _TriButtonState extends State<TriButton> {
Weight selectedWeight;
#override
Widget build(BuildContext context) {
return Center(
child: Container(
constraints: BoxConstraints(maxWidth: 300),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: RectButton(
buttonChild: GOAL TO ENTER TITLE HERE,
onPress: () {
setState(() {
selectedWeight = Weight.adjusted;
});
},
bgColor: selectedWeight == Weight.adjusted
? Colors.orange[600]
: Colors.grey[600],
),
),
When using a StatefulWidget you need to use "widget.property" in your implementation.
In your case
Expanded(
child: RectButton(
buttonChild: Text(widget.title1),
onPress: () {
setState(() {
selectedWeight = Weight.adjusted;
});
},
bgColor: selectedWeight == Weight.adjusted
? Colors.orange[600]
: Colors.grey[600],
),
),
Expanded(
child: RectButton(
buttonChild: Text(widget.title2),
onPress: () {
setState(() {
selectedWeight = Weight.adjusted;
});
},
bgColor: selectedWeight == Weight.adjusted
? Colors.orange[600]
: Colors.grey[600],
),
),
.....