How to change price on button pressed in flutter - flutter

SCENARIO
I have a dummy image, under image there is price and under price there three widget
Two widget are buttons (+) and (-) and one widget is Text('1') which is a QTY.
QUESTION
When i click on the button it increment and decrement the number but how do i change the price based on QTY (if QTY is 2 then price must be double)
class Quantities extends StatefulWidget {
final productprice;
final productimage;
Quantities({this.productprice, this.productimage});
#override
_QuantitiesState createState() => _QuantitiesState(productprice,productimage);
}
class _QuantitiesState extends State<Quantities> {
int counter = 1;
final productprice;
final productimage;
_QuantitiesState(this.productprice, this.productimage);
void increment() {
setState(() {
counter++;
});
}
void decrement() {
setState(() {
counter--;
});
}
#override
Widget build(BuildContext context) {
return PlatformScaffold(
appBar: PlatformAppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Quantities'),
),
body: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ListView(
children: <Widget>[
new Container(
height: 200.0,
child: GridTile(
child: Container(
color: Colors.white,
child: Image.asset(productimage),),),),
Center(
child: Text(
productprice,),),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: PlatformButton(
onPressed: () {
decrement();
if (counter < 1) {
counter = 1;
}
},
child: Text(
'-',
),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),
),
Text(
'$counter',
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: PlatformButton(
onPressed: () {
increment();
},
child: Text(
'+',
style: TextStyle(color: Colors.white, fontSize: 30.0),
),
androidFlat: (_) =>
MaterialFlatButtonData(color: Colors.cyan),
ios: (_) => CupertinoButtonData(
color: Colors.cyan
)),

this is the full code example:
import 'package:flutter/material.dart';
import 'package:project_app/proyects/home.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Product price',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Quantities(productimage: "",productprice: "20$",),
);
}
}
class Quantities extends StatefulWidget {
final productprice;
final productimage;
Quantities({this.productprice, this.productimage});
#override
_QuantitiesState createState() =>
_QuantitiesState(productprice, productimage);
}
class _QuantitiesState extends State<Quantities> {
int counter = 1;
final productprice;
double finalprice;
final productimage;
final productp =productprice.replaceAll(new RegExp(r'\$'), '');
_QuantitiesState(this.productprice, this.productimage);
void increment() {
setState(() {
counter++;
finalprice=double.parse(productp)*counter;
});
}
void decrement() {
setState(() {
counter--;
finalprice=double.parse(productp)*counter;
});
}
#override
void initState() {
super.initState();
finalprice= double.parse(productp);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.lightBlue[900],
title: Text('Quantities'),
),
body: Padding(
padding: const EdgeInsets.only(top: 10.0),
child: ListView(
children: <Widget>[
Center(
child: Text(
finalprice.toString(),
),
),
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: FlatButton(
onPressed: () {
if (counter > 1) {
decrement();
}
},
child: Text(
'-',
),
),
),
Text(
'$counter',
),
Padding(
padding: const EdgeInsets.only(left: 10.0),
child: FlatButton(
onPressed: () {
increment();
},
child: Text(
'+',
style:
TextStyle(color: Colors.white, fontSize: 30.0),
),
),
),
]),
),
],
),
));
}
}

In this case you need to multiply the value of product price in
setstate(){
productprice=productprice*counter;
}
or
productprice*=counter;

Related

Flutter:How can i change the color of selected menu item from drawer

I am creating an app in flutter, I have got some issue in drawer. I want to change the color of the selected drawer item.Here is my full code it looks fine to me but its not working for me... please help me find out what i am doing wrong
class _DrawerClassState extends State<DrawerClass> {
Here is my full code it looks fine to me but its not working for me... please help me find out what i am doing wrong
List<String> menuStrings = [
'HOME',
'NOTIFICATIONS',
'PARTNERS',
'LOCATIONS',
'FEEDBACK',
'CONTACT US',
'AWARDS'
];
Here is my full code it looks fine to me but its not working for me... please help me find out what i am doing wrong
List menuScreens = [
HomeScreen(),
Notifications(),
Partners(),
Locations(),
FeedbackScreen(),
const ContactUs(),
Awards()
];
Here is my full code it looks fine to me but its not working for me... please help me find out what i am doing wrong
List<bool> isHighlighted = [false, false, false, false, true, false, false];
#override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.black,
),
child: Drawer(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
drawerTop("HI USER"),
ListView.builder(
shrinkWrap: true,
itemCount: menuScreens.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () {
for (int i = 0; i < isHighlighted.length; i++) {
setState(() {
if (index == i) {
isHighlighted[index] = true;
} else {
//the condition to change the highlighted item
isHighlighted[i] = false;
}
});
}
},
child: drawerItems(
context,
menuStrings[index],
menuScreens[index],
isHighlighted[index] ? Colors.amber : Colors.white,
),
);
},
),
],
),
),
);
}
}
Here is the method drawerItems() to build drawer items
drawerItems(BuildContext context, String title, path, Color color) {
return Padding(
padding: EdgeInsets.only(
top: 0.0, left: MediaQuery.of(context).size.width * 0.1),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
GestureDetector(
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: ((context) => path)));
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
title,
style: TextStyle(
color: color,
fontFamily: "Raleway Reg",
fontSize: 23,
letterSpacing: 2),
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: const Divider(
thickness: 1,
color: Colors.white,
height: 3,
),
),
]));
}
Update your drawerItems
drawerItems(BuildContext context, String title, path, Color color) {
return Container(
color: color,
padding: EdgeInsets.only(
top: 0.0, left: MediaQuery.of(context).size.width * 0.1),
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
GestureDetector(
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: ((context) => path)));
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: Text(
title,
style: TextStyle(
color: color,
fontFamily: "Raleway Reg",
fontSize: 23,
letterSpacing: 2),
),
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: const Divider(
thickness: 1,
color: Colors.white,
height: 3,
),
),
]));
}
the root widget that is returned from the method, change it from Padding to Container and give it a color
I think it's a very complex solution to solve this simple task in Flutter.
I suggest my solution:
Publish it on my git:
https://github.com/igdmitrov/flutter-drawer
Create a new Abstract Page State:
abstract class MyPageState<T extends StatefulWidget> extends State {
List<Widget> drawerItems(BuildContext context) {
return menuItems
.map(
(item) => ListTile(
leading: const Icon(Icons.my_library_books),
title: Text(
item['menuName'] as String,
style: TextStyle(
color: isHighlighted[menuItems.toList().indexOf(item)]
? Colors.amber
: Colors.grey),
),
onTap: () {
isHighlighted = isHighlighted.map((mark) => false).toList();
isHighlighted[menuItems.toList().indexOf(item)] = true;
Navigator.of(context).push(MaterialPageRoute(
builder: ((context) => item['route'] as Widget)));
},
),
)
.toList();
}
}
Create drawer.dart file with code:
final menuItems = {
{'menuName': 'HOME', 'route': const HomeScreen()},
{'menuName': 'NOTIFICATIONS', 'route': const Notifications()},
};
List<bool> isHighlighted = [false, false];
And create pages:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
MyPageState<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends MyPageState<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Main page'),
),
drawer: Drawer(
child: ListView(
children: [
const Text("HI USER"),
...drawerItems(context),
],
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'New app',
),
],
),
),
);
}
}
And Notifications page:
class Notifications extends StatefulWidget {
static String routeName = '/notifications';
const Notifications({Key? key}) : super(key: key);
#override
MyPageState<Notifications> createState() => _NotificationsState();
}
class _NotificationsState extends MyPageState<Notifications> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Notifications'),
),
drawer: Drawer(
child: ListView(
children: [
const Text("HI USER"),
...drawerItems(context),
],
),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
'Notifications page',
),
],
),
),
);
}
}

Flutter nested widgets setState does not work as intended

I have the following structure:
MainBlock. main statefull widget. contains two widgets BlockA and BlockB.
BlockA. contains a text and a button.
BlockB. contains another widget, BlockBCard, which will be used several times (two times in this example).
What works as intended? When I click on the button in BlockA, the content of the text field in BlockA and BlockBCard changers as desired.
Now to my problem:
In BlockB. In order to use setState, I changed BlockB to a StatefulWidget.
Clicking on the button in the BlockBCard, changes the text field in both BlockBCard’s as desired.
But the content of the text field in BlockA does not change.
how can I implement the following:
Click on the button in one of the BlockBCard’s, both the text field in BlockA and the two text fields in BlockBCard change?
Click on the button in one of the BlockBCard’s, the text field in BlockA changes and the text field in the BlockBCard changes but the text field in the second BlockBCard does not change.
Sample Code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
int testCounter = 0;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
// ------------------------------------ Stateless Widget <<<
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: BlockA(
counter: testCounter,
button: () {
setState(() {
testCounter++;
});
},
),
),
Expanded(
child: BlockB(),
),
],
),
),
);
}
}
class BlockA extends StatelessWidget {
final int counter;
final Function button;
BlockA({this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
class BlockB extends StatefulWidget {
#override
_BlockBState createState() => _BlockBState();
}
class _BlockBState extends State<BlockB> {
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: BlockBCard(
counter: testCounter,
button: () {
setState(() {
testCounter++;
});
},
),
),
Expanded(
child: BlockBCard(
counter: testCounter,
),
),
],
),
);
}
}
class BlockBCard extends StatelessWidget {
final int counter;
final Function button;
BlockBCard({this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF4C93C7),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
OK, I have now improved my code so that the button in the BlockBCard's calls a function myBrain that executes a calculation, the result of which is output in BlockA.
Now I would like to increase the text field in the BlockBCard's by 1, but only in the respective card in which the button is pressed and not in all cards. With my current code, all cards are incorrectly increased by 1.
In this example there are only two cards, but in the implementation there will be multiple cards.
Here is my current code. to simplify the example, I removed BlockB and placed the BlockBCard's directly into the MainBlock:
How can I increase the text field in the BlockBCard's by 1, but only in the respective card in which the button is pressed and not in all cards?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO MainBlock >>>
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
int totalCounter = 0;
int singleCounter = 0;
void myBrain() {
totalCounter = totalCounter + 5;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: BlockA(
counter: totalCounter,
button: () {
setState(() {
totalCounter = 0;
});
},
),
),
Expanded(
child: BlockBCard(
counter: singleCounter,
button: () {
setState(() {
myBrain();
singleCounter++;
});
},
),
),
Expanded(
child: BlockBCard(
counter: singleCounter,
button: () {
setState(() {
myBrain();
singleCounter++;
});
},
),
),
],
),
),
);
}
}
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO MainBlock <<<
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO BlockA >>>
class BlockA extends StatelessWidget {
final int counter;
final Function button;
BlockA({this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO BlockA <<<
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO BlockBCard >>>
class BlockBCard extends StatelessWidget {
final int counter;
final Function button;
BlockBCard({this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF4C93C7),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
// OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO BlockBCard <<<
You got the issue because when you change the value of blockB it could not rebuild ta blockA but it change the global value if you will want to change the blockA's from blockB you should pass as like blockA.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
int testCounter = 0;
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
// ------------------------------------ Stateless Widget <<<
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: BlockA(
counter: testCounter,
button: () {
setState(() {
testCounter++;
});
},
),
),
Expanded(
child: BlockB(
counter: testCounter,
button: () {
setState(() {
testCounter++;
});
}),
),
],
),
),
);
}
}
class BlockA extends StatelessWidget {
final int counter;
final Function button;
BlockA({this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
class BlockB extends StatefulWidget {
final int counter;
final Function button;
BlockB({this.counter, this.button});
#override
_BlockBState createState() => _BlockBState();
}
class _BlockBState extends State<BlockB> {
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: BlockBCard(
counter: testCounter,
button:widget.button,
),
),
Expanded(
child: BlockBCard(
counter: testCounter,
),
),
],
),
);
}
}
class BlockBCard extends StatelessWidget {
final int counter;
final Function button;
BlockBCard({this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF4C93C7),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
As #Jahidul Islam explained, you have to pass your data from MainBlock to BlocB as you do from MainBlock to BlocA.
In general in Flutter, you want to avoid using mutable global variable precisely for that reason. When a variable update, flutter does not know about it. If you call setState the widget tree bellow will be rebuild.
This is why you will often hear "Lift the state up" because the state has to be contained in a high enough widget so that it can be passed down through the widget tree to every widget that needs it. In your case, since BlocA and BlockBCard need the counter, it has to be created inside there lower common ancestor: MainBlock.
Here is the concrete implementation but the most important thing is to have understood the reasoning explained above:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MainBlock(),
);
}
}
class MainBlock extends StatefulWidget {
#override
_MainBlockState createState() => _MainBlockState();
}
class _MainBlockState extends State<MainBlock> {
int testCounter = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF122C39),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: BlockA(
counter: testCounter,
button: () {
setState(() {
testCounter++;
});
},
),
),
Expanded(
child: BlockB(
counter: testCounter,
button: () {
setState(() {
testCounter++;
});
},
),
),
],
),
),
);
}
}
class BlockA extends StatelessWidget {
final int counter;
final VoidCallback button;
BlockA({required this.counter, required this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button,
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
class BlockB extends StatelessWidget {
final int counter;
final VoidCallback button;
BlockB({required this.counter, required this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: BlockBCard(
counter: counter,
button: button,
),
),
Expanded(
child: BlockBCard(
counter: counter,
),
),
],
),
);
}
}
class BlockBCard extends StatelessWidget {
final int counter;
final VoidCallback? button;
BlockBCard({required this.counter, this.button});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(30.0),
color: Color(0xFF4C93C7),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Center(
child: Text(
counter.toString(),
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
Center(
child: GestureDetector(
onTap: button ?? (() {}),
child: Text(
'Button',
style: TextStyle(
color: Color(0xFFFFFFFF),
fontSize: 22.0,
),
),
),
),
],
),
);
}
}
If we refresh the MainBlock it's children will also get the updated state. We can use callback for it.
On BlocKB
class BlockB extends StatefulWidget {
final VoidCallback ontap;
const BlockB({
Key? key,
required this.ontap,
}) : super(key: key);
#override
_BlockBState createState() => _BlockBState();
}
class _BlockBState extends State<BlockB> {
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(10.0),
color: Color(0xFF265672),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: BlockBCard(
counter: testCounter,
button: () {
// setState(() { /// we dont need it while parent widget will refress it
testCounter++;
// });
widget.ontap();
},
),
),
Expanded(
child: BlockBCard(
counter: testCounter,
button: () {
/// you may also wanted to increment here
testCounter++;
widget.ontap();
},
),
),
],
),
);
}
}
On MainBlock
Expanded(
child: BlockB(
ontap: () {
setState(() {});
},
),
),

Create a new card when FAB is clicked

I need create a card, when the FAB is clicked, like a list or just create a card into Column, like this image:
enter image description here
Here's one way:
import 'package:flutter/material.dart';
void main() async {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()));
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Widget> cardWidget = [];
buildCard() {
setState(() {
cardWidget.add(
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(20.0),
child: TextFormField(),
),
Padding(
padding: EdgeInsets.all(20.0),
child: TextFormField(),
),
RaisedButton(
onPressed: () {},
padding: EdgeInsets.only(left: 20.0, right: 20.0, top: 10.0, bottom: 10.0),
color: Colors.green,
child: Text(
'Criar',
style: TextStyle(
color: Colors.white
),
),
)
],
),
)
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.blue[900],
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.blue[900]
),
floatingActionButton: FloatingActionButton(
onPressed: buildCard,
backgroundColor: Colors.green,
child: Icon(
Icons.add,
color: Colors.white,
),
),
body: Column(
children: cardWidget.map((data) {
return data;
}).toList()
),
);
}
}
This method may not be the best way for you so I encourage you to try something new on your own!

Listview with Checkbox using StatefulWidget(setState)

I am trying to develop an app in flutter, that has topics that the user can select and check box state will change when i scroll on listview check box state will not collapse and finally user give the submit the value are will bring out.i tried i am not able do that.
the error message shows:
The method 'setState' isn't defined for the class 'ItemDepletionList'.
Try correcting the name to the name of an existing method, or defining a method named 'setState'
class ItemDepletion extends StatefulWidget {
#override
_GetShaftsState createState() => _GetShaftsState();
}
class _GetShaftsState extends State<ItemDepletion> {
ItemDepletionBloc _bloc;
String json =
'{"RECORD_ID": "0", "REQTYPE": "ITEMDEPELTION", "CLINIC_ID": "1012"}';
#override
void initState() {
super.initState();
_bloc = ItemDepletionBloc(json);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.0,
automaticallyImplyLeading: false,
title: Text('Chucky Categories',
style: TextStyle(color: Colors.white, fontSize: 20)),
backgroundColor: Color(0xFF333333),
),
backgroundColor: Color(0xFF333333),
body: RefreshIndicator(
onRefresh: () => _bloc.fetchCategories(json),
child: StreamBuilder<Response<List<Idepeltion>>>(
stream: _bloc.chuckListStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
switch (snapshot.data.status) {
case Status.LOADING:
return Loading(loadingMessage: snapshot.data.message);
break;
case Status.COMPLETED:
return ItemDepletionList(
itemdepletionlst: snapshot.data.data);
break;
case Status.ERROR:
return Error(
errorMessage: snapshot.data.message,
onRetryPressed: () => _bloc.fetchCategories(json),
);
break;
}
}
return Container();
},
),
),
);
}
#override
void dispose() {
_bloc.dispose();
super.dispose();
}
}
class ItemDepletionList extends StatelessWidget {
// final Itemdepeltion categoryList;
final List<Idepeltion> itemdepletionlst;
const ItemDepletionList({Key key, this.itemdepletionlst}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new Myappbar(title: new Text("Home Page")),
body: Column(children: [
Expanded(
child: ListView.builder(
itemCount: itemdepletionlst.length,
itemBuilder: (context, index) {
return ListTile(
title: new Container(
child: Row(
children: <Widget>[
new Checkbox(
value: itemdepletionlst[index].isCheck,
onChanged: (bool value) {
setState(() {
itemdepletionlst[index].isCheck = value;
});
}),
new Expanded(
child: new Container(
padding: new EdgeInsets.only(left: 8.0, right: 8.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Text(
'${itemdepletionlst[index].itemName}',
style: new TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 16.0,
),
),
new Text(
'${itemdepletionlst[index].category}',
style: new TextStyle(color: Colors.grey),
),
],
),
),
),
new Expanded(
child: GestureDetector(
onTap: () {
selectedItem(
context, itemdepletionlst[index].suggQtyUnit);
},
child: new Container(
padding: new EdgeInsets.only(left: 8.0, right: 8.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Text(
'${itemdepletionlst[index].suggReorderQty} ${itemdepletionlst[index].suggQtyUnit}',
style: new TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontSize: 16.0,
),
),
new Text(
'${itemdepletionlst[index].manuf}',
style: new TextStyle(color: Colors.grey),
),
],
),
),
)),
],
)));
},
),
),
RaisedButton(
// onPressed: getCheckboxItems,
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF09a3c8),
Color(0xFF39B9B4),
Color(0xFF0fb188),
],
),
),
padding: const EdgeInsets.all(10.0),
child: const Text('Submit',
style: TextStyle(fontSize: 20, color: Colors.white)),
),
),
])
);
}
}
Your ItemDepletionList class is stateless and You are trying to call setstate in it because of that you are getting that error. make it Stateful then it will work.
replace Following line.
class ItemDepletionList extends StatelessWidget {
With this
class ItemDepletionList extends StatefulWidget {
final List<Idepeltion> itemdepletionlst;
ItemDepletionList({this.itemdepletionlst});
#override
_ItemDepletionListState createState() => _ItemDepletionListState();
}
class _ItemDepletionListState extends State<ItemDepletionList> {
And now to access itemdepletionlst you have use widget.
widget.itemdepletionlst

Flutter: BottomNavigationBar rebuilds Page on change of tab

I have a problem with my BottomNavigationBar in Flutter. I want to keep my page alive if I change the tabs.
here my implementation
BottomNavigation
class Home extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _HomeState();
}
}
class _HomeState extends State<Home> {
int _currentIndex = 0;
List<Widget> _children;
final Key keyOne = PageStorageKey("IndexTabWidget");
#override
void initState() {
_children = [
IndexTabWidget(key: keyOne),
PlaceholderWidget(Colors.green),
NewsListWidget(),
ShopsTabWidget(),
PlaceholderWidget(Colors.blue),
];
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(MyApp.appName),
textTheme: Theme.of(context).textTheme.apply(
bodyColor: Colors.black,
displayColor: Colors.blue,
),
),
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
key: IHGApp.globalKey,
fixedColor: Colors.green,
type: BottomNavigationBarType.fixed,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Container(height: 0.0),
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
title: Container(height: 0.0),
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
title: Container(height: 0.0),
),
BottomNavigationBarItem(
icon: Icon(Icons.perm_contact_calendar),
title: Container(height: 0.0),
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
title: Container(height: 0.0),
),
],
),
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
Column buildButtonColumn(IconData icon) {
Color color = Theme.of(context).primaryColor;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(icon, color: color),
],
);
}
}
This is my index page (first tab):
class IndexTabWidget extends StatefulWidget {
IndexTabWidget({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return new IndexTabState();
}
}
class IndexTabState extends State<IndexTabWidget>
with AutomaticKeepAliveClientMixin {
List<News> news = List();
FirestoreNewsRepo newsFirestore = FirestoreNewsRepo();
#override
Widget build(BuildContext context) {
return Material(
color: Colors.white,
child: new Container(
child: new SingleChildScrollView(
child: new ConstrainedBox(
constraints: new BoxConstraints(),
child: new Column(
children: <Widget>[
HeaderWidget(
CachedNetworkImageProvider(
'https://static1.fashionbeans.com/wp-content/uploads/2018/04/50-barbershop-top-savill.jpg',
),
"",
),
AboutUsWidget(),
Padding(
padding: const EdgeInsets.all(16.0),
child: SectionTitleWidget(title: StringStorage.salonsTitle),
),
StreamBuilder(
stream: newsFirestore.observeNews(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
news = snapshot.data;
return Column(
children: <Widget>[
ShopItemWidget(
AssetImage('assets/images/picture.png'),
news[0].title,
news[0],
),
ShopItemWidget(
AssetImage('assets/images/picture1.png'),
news[1].title,
news[1],
)
],
);
}
},
),
Padding(
padding: const EdgeInsets.only(
left: 16.0, right: 16.0, bottom: 16.0),
child: SectionTitleWidget(title: StringStorage.galleryTitle),
),
GalleryCategoryCarouselWidget(),
],
),
),
),
),
);
}
#override
bool get wantKeepAlive => true;
}
So if I switch from my index tab to any other tab and back to the index tab, the index tab will always rebuild. I debugged it and saw that the build function is always being called on the tab switch.
Could you guys help me out with this issue?
Thank you a lot
Albo
None of the previous answers worked out for me.
The solution to keep the pages alive when switching the tabs is wrapping your Pages in an IndexedStack.
class Tabbar extends StatefulWidget {
Tabbar({this.screens});
static const Tag = "Tabbar";
final List<Widget> screens;
#override
State<StatefulWidget> createState() {
return _TabbarState();
}
}
class _TabbarState extends State<Tabbar> {
int _currentIndex = 0;
Widget currentScreen;
#override
Widget build(BuildContext context) {
var _l10n = PackedLocalizations.of(context);
return Scaffold(
body: IndexedStack(
index: _currentIndex,
children: widget.screens,
),
bottomNavigationBar: BottomNavigationBar(
fixedColor: Colors.black,
type: BottomNavigationBarType.fixed,
onTap: onTabTapped,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.format_list_bulleted),
title: new Text(_l10n.tripsTitle),
),
BottomNavigationBarItem(
icon: new Icon(Icons.settings),
title: new Text(_l10n.settingsTitle),
)
],
),
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}
You need to wrap every root page (the first page you see when you press a bottom navigation item) with a navigator and put them in a Stack.
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final int _pageCount = 2;
int _pageIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: _body(),
bottomNavigationBar: _bottomNavigationBar(),
);
}
Widget _body() {
return Stack(
children: List<Widget>.generate(_pageCount, (int index) {
return IgnorePointer(
ignoring: index != _pageIndex,
child: Opacity(
opacity: _pageIndex == index ? 1.0 : 0.0,
child: Navigator(
onGenerateRoute: (RouteSettings settings) {
return new MaterialPageRoute(
builder: (_) => _page(index),
settings: settings,
);
},
),
),
);
}),
);
}
Widget _page(int index) {
switch (index) {
case 0:
return Page1();
case 1:
return Page2();
}
throw "Invalid index $index";
}
BottomNavigationBar _bottomNavigationBar() {
final theme = Theme.of(context);
return new BottomNavigationBar(
fixedColor: theme.accentColor,
currentIndex: _pageIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.list),
title: Text("Page 1"),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle),
title: Text("Page 2"),
),
],
onTap: (int index) {
setState(() {
_pageIndex = index;
});
},
);
}
}
The pages will be rebuild but you should separate your business logic from you UI anyway. I prefer to use the BLoC pattern but you can also use Redux, ScopedModel or InhertedWidget.
Just use an IndexedStack
IndexedStack(
index: selectedIndex,
children: <Widget> [
ProfileScreen(),
MapScreen(),
FriendsScreen()
],
)
I'm not sure but CupertinoTabBar would help.
If you don't want it, this video would be great url.
import 'dart:async';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => new _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final List<dynamic> pages = [
new Page1(),
new Page2(),
new Page3(),
new Page4(),
];
int currentIndex = 0;
#override
Widget build(BuildContext context) {
return new WillPopScope(
onWillPop: () async {
await Future<bool>.value(true);
},
child: new CupertinoTabScaffold(
tabBar: new CupertinoTabBar(
iconSize: 35.0,
onTap: (index) {
setState(() => currentIndex = index);
},
activeColor: currentIndex == 0 ? Colors.white : Colors.black,
inactiveColor: currentIndex == 0 ? Colors.green : Colors.grey,
backgroundColor: currentIndex == 0 ? Colors.black : Colors.white,
currentIndex: currentIndex,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.looks_one),
title: Text(''),
),
BottomNavigationBarItem(
icon: Icon(Icons.looks_two),
title: Text(''),
),
BottomNavigationBarItem(
icon: Icon(Icons.looks_3),
title: Text(''),
),
BottomNavigationBarItem(
icon: Icon(Icons.looks_4),
title: Text(''),
),
],
),
tabBuilder: (BuildContext context, int index) {
return new DefaultTextStyle(
style: const TextStyle(
fontFamily: '.SF UI Text',
fontSize: 17.0,
color: CupertinoColors.black,
),
child: new CupertinoTabView(
routes: <String, WidgetBuilder>{
'/Page1': (BuildContext context) => new Page1(),
'/Page2': (BuildContext context) => new Page2(),
'/Page3': (BuildContext context) => new Page3(),
'/Page4': (BuildContext context) => new Page4(),
},
builder: (BuildContext context) {
return pages[currentIndex];
},
),
);
},
),
);
}
}
class Page1 extends StatefulWidget {
#override
_Page1State createState() => _Page1State();
}
class _Page1State extends State<Page1> {
String title;
#override
void initState() {
title = 'Page1';
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(title),
leading: new IconButton(
icon: new Icon(Icons.text_fields),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Page13()));
},
)),
body: new Center(
child: new Text(title),
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Page2'),
leading: new IconButton(
icon: new Icon(Icons.airline_seat_flat_angled),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Page12()));
},
)),
body: new Center(
child: Column(
children: <Widget>[
CupertinoSlider(
value: 25.0,
min: 0.0,
max: 100.0,
onChanged: (double value) {
print(value);
}
),
],
),
),
);
}
}
class Page3 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Page3'),
),
body: new Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new RaisedButton(
child: new Text('Cupertino'),
textColor: Colors.white,
color: Colors.red,
onPressed: () {
List<int> list = List.generate(10, (int i) => i + 1);
list.shuffle();
var subList = (list.sublist(0, 5));
print(subList);
subList.forEach((li) => list.remove(li));
print(list);
}
),
new SizedBox(height: 30.0),
new RaisedButton(
child: new Text('Android'),
textColor: Colors.white,
color: Colors.lightBlue,
onPressed: () {
var mes = 'message';
var messa = 'メッセージ';
var input = 'You have a new message';
if (input.contains(messa) || input.contains(mes)) {
print('object');
} else {
print('none');
}
}
),
],
),
),
);
}
}
class Page4 extends StatelessWidget {
static List<int> ints = [1, 2, 3, 4, 5];
static _abc() {
print(ints.last);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Page4'),
),
body: new Center(
child: new RaisedButton(
child: new Text('Static', style: new TextStyle(color: Colors.white)),
color: Colors.lightBlue,
onPressed: _abc,
)),
);
}
}
class Page12 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Page12'),
actions: <Widget>[
new FlatButton(
child: new Text('GO'),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => Page13()));
},
)
],
),
body: new Center(
child: new RaisedButton(
child: new Text('Swiper', style: new TextStyle(color: Colors.white)),
color: Colors.redAccent,
onPressed: () {},
)),
);
}
}
class Page13 extends StatefulWidget {
#override
_Page13State createState() => _Page13State();
}
class _Page13State extends State<Page13> with SingleTickerProviderStateMixin {
final List<String> _productLists = Platform.isAndroid
? [
'android.test.purchased',
'point_1000',
'5000_point',
'android.test.canceled',
]
: ['com.cooni.point1000', 'com.cooni.point5000'];
String _platformVersion = 'Unknown';
List<IAPItem> _items = [];
List<PurchasedItem> _purchases = [];
#override
void initState() {
super.initState();
initPlatformState();
}
Future<void> initPlatformState() async {
String platformVersion;
try {
platformVersion = await FlutterInappPurchase.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
var result = await FlutterInappPurchase.initConnection;
print('result: $result');
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
// refresh items for android
String msg = await FlutterInappPurchase.consumeAllItems;
print('consumeAllItems: $msg');
}
Future<Null> _buyProduct(IAPItem item) async {
try {
PurchasedItem purchased = await FlutterInappPurchase.buyProduct(item.productId);
print('purchased: ${purchased.toString()}');
} catch (error) {
print('$error');
}
}
Future<Null> _getProduct() async {
List<IAPItem> items = await FlutterInappPurchase.getProducts(_productLists);
print(items);
for (var item in items) {
print('${item.toString()}');
this._items.add(item);
}
setState(() {
this._items = items;
this._purchases = [];
});
}
Future<Null> _getPurchases() async {
List<PurchasedItem> items = await FlutterInappPurchase.getAvailablePurchases();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}
Future<Null> _getPurchaseHistory() async {
List<PurchasedItem> items = await FlutterInappPurchase.getPurchaseHistory();
for (var item in items) {
print('${item.toString()}');
this._purchases.add(item);
}
setState(() {
this._items = [];
this._purchases = items;
});
}
List<Widget> _renderInApps() {
List<Widget> widgets = this
._items
.map((item) => Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 5.0),
child: Text(
item.toString(),
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
),
),
),
FlatButton(
color: Colors.orange,
onPressed: () {
print("---------- Buy Item Button Pressed");
this._buyProduct(item);
},
child: Row(
children: <Widget>[
Expanded(
child: Container(
height: 48.0,
alignment: Alignment(-1.0, 0.0),
child: Text('Buy Item'),
),
),
],
),
),
],
),
),
))
.toList();
return widgets;
}
List<Widget> _renderPurchases() {
List<Widget> widgets = this
._purchases
.map((item) => Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
child: Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(bottom: 5.0),
child: Text(
item.toString(),
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
),
),
)
],
),
),
))
.toList();
return widgets;
}
#override
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width-20;
double buttonWidth=(screenWidth/3)-20;
return new Scaffold(
appBar: new AppBar(),
body: Container(
padding: EdgeInsets.all(10.0),
child: ListView(
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Text(
'Running on: $_platformVersion\n',
style: TextStyle(fontSize: 18.0),
),
),
Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: buttonWidth,
height: 60.0,
margin: EdgeInsets.all(7.0),
child: FlatButton(
color: Colors.amber,
padding: EdgeInsets.all(0.0),
onPressed: () async {
print("---------- Connect Billing Button Pressed");
await FlutterInappPurchase.initConnection;
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment(0.0, 0.0),
child: Text(
'Connect Billing',
style: TextStyle(
fontSize: 16.0,
),
),
),
),
),
Container(
width: buttonWidth,
height: 60.0,
margin: EdgeInsets.all(7.0),
child: FlatButton(
color: Colors.amber,
padding: EdgeInsets.all(0.0),
onPressed: () async {
print("---------- End Connection Button Pressed");
await FlutterInappPurchase.endConnection;
setState(() {
this._items = [];
this._purchases = [];
});
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment(0.0, 0.0),
child: Text(
'End Connection',
style: TextStyle(
fontSize: 16.0,
),
),
),
),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
width: buttonWidth,
height: 60.0,
margin: EdgeInsets.all(7.0),
child: FlatButton(
color: Colors.green,
padding: EdgeInsets.all(0.0),
onPressed: () {
print("---------- Get Items Button Pressed");
this._getProduct();
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment(0.0, 0.0),
child: Text(
'Get Items',
style: TextStyle(
fontSize: 16.0,
),
),
),
)),
Container(
width: buttonWidth,
height: 60.0,
margin: EdgeInsets.all(7.0),
child: FlatButton(
color: Colors.green,
padding: EdgeInsets.all(0.0),
onPressed: () {
print(
"---------- Get Purchases Button Pressed");
this._getPurchases();
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment(0.0, 0.0),
child: Text(
'Get Purchases',
style: TextStyle(
fontSize: 16.0,
),
),
),
)),
Container(
width: buttonWidth,
height: 60.0,
margin: EdgeInsets.all(7.0),
child: FlatButton(
color: Colors.green,
padding: EdgeInsets.all(0.0),
onPressed: () {
print(
"---------- Get Purchase History Button Pressed");
this._getPurchaseHistory();
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
alignment: Alignment(0.0, 0.0),
child: Text(
'Get Purchase History',
style: TextStyle(
fontSize: 16.0,
),
),
),
)),
]),
],
),
Column(
children: this._renderInApps(),
),
Column(
children: this._renderPurchases(),
),
],
),
],
),
),
);
}
}
Use IndexedStack widget:
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: IndexedStack(
index: _currentIndex,
children: const [
HomePage(),
SettingsPage(),
],
),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (int index) => setState(() => _currentIndex = index),
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: 'Settings'),
],
),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
print('build home');
return Center(child: Text('Home'));
}
}
class SettingsPage extends StatelessWidget {
const SettingsPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
print('build settings');
return Center(child: Text('Settings'));
}
}
Make sure the IndexedStack children widget list is constant. This will prevent the widgets from rebuilding when setState() is called.
IndexedStack(
index: _currentIndex,
children: const [
HomeWidget(),
SettingsWidget(),
],
),
The problem with IndexedStack is that all the widgets will be built at the same time when IndexedStack is initialized. For small widgets (like the example above), it won't be a problem. But for big widgets, you may see some performance issues.
Consider using the lazy_load_indexed_stack package. According to the package:
[LazyLoadIndexedStack widget] builds the required widget only when it is needed, and returns the pre-built widget when it is needed again
Again, make sure the LazyLoadIndexedStack children widgets are constant, otherwise they will keep rebuilding when setState is called.
If, you just need to remember the scroll position inside a list, the best option is to simply use a PageStoreKey object for the key property:
#override
Widget build(BuildContext context) {
return Container(
child: ListView.builder(
key: PageStorageKey<String>('some-list-key'),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: items.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () => _onElementTapped(index),
child: makeCard(items[index])
);
},
),
);
}
According to https://docs.flutter.io/flutter/widgets/PageStorageKey-class.html, this should work on ANY scrollable widget.
if i use the IndexedStack in the body it is loading only the main screen content not every other screen which is present in the bottom nativation bar.
Using IndexedStack with bloc pattern solved everthing.