Error updating UI, setState() not working in flutter - flutter

I have two buttons on flutter screen (add to cart and remove from cart).
cartQuantity is a variable I have declared in my build() method to keep a track of users cart quantity.
When the user presses the add button, the UI for quantity x rate should change which doesn't seem to happen.
The Row widget contains 'REMOVE' button, user's cart quantity and 'ADD' button respectively.
class ItemBottomSheet extends StatefulWidget {
final RestaurantItems restaurantItem;
final Restaurant restaurant;
const ItemBottomSheet({
this.restaurantItem,
this.restaurant,
});
#override
_ItemBottomSheetState createState() => _ItemBottomSheetState();
}
class _ItemBottomSheetState extends State<ItemBottomSheet> {
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final cartItems = Provider.of<Cart>(context).getCartItems;
final index = cartItems.indexWhere((cartItem) =>
cartItem.id == widget.restaurantItem.id &&
cartItem.restaurantId == widget.restaurant.id);
int restQuantity = widget.restaurantItem.quantity;
int cartQuantity = 0;
if (index != -1) {
cartQuantity = cartItems[index].quantity;
}
return Container(
decoration: new BoxDecoration(
color: darkThemeColour,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: new BoxDecoration(
color: Colors.transparent,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(20.0),
topRight: const Radius.circular(20.0))),
height: size.height * 0.21,
width: double.infinity,
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
child: Image.network(
widget.restaurantItem.imageUrl,
fit: BoxFit.cover,
),
),
),
Row(
// crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
// SizedBox(
// height: 12,
// width: 12,
// child: SvgPicture.asset(
// 'lib/assets/icons/green-circle.svg',
// color: restaurantItem.isVeg ? Colors.green : Colors.red,
// ),
// ),
Padding(
padding: const EdgeInsets.only(top: 25, left: 18),
child: Text(
widget.restaurantItem.name,
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 21,
fontWeight: FontWeight.w600),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 17),
child: Text(
'₹${widget.restaurantItem.price}',
style: TextStyle(
color: Colors.green,
fontFamily: 'Raleway',
fontSize: 18,
fontWeight: FontWeight.w900),
),
),
Padding(
padding: const EdgeInsets.only(top: 27),
child: Text(
'Pickup Between',
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 14,
fontWeight: FontWeight.w300),
),
),
Padding(
padding: const EdgeInsets.only(top: 15),
child: Text(
'${DateFormat.jm().format(widget.restaurant.pickupTime.start)} - ${DateFormat.jm().format(widget.restaurant.pickupTime.end)}',
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 17,
fontWeight: FontWeight.w400),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(top: 25, left: 18),
child: ClipOval(
child: Material(
color: index == -1 ||
cartItems[index].quantity == 0 ||
widget.restaurantItem.quantity <= 1
? Colors.grey
: Colors.green, // button color
child: InkWell(
splashColor: Colors.white30, // inkwell color
child: SizedBox(
width: 60,
height: 60,
child: Icon(
Icons.remove,
color: Colors.white,
size: 28,
)),
onTap: () {},
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 20),
child: Text(
cartQuantity > 0
? '$cartQuantity x ₹${widget.restaurantItem.price}'
: '₹${widget.restaurantItem.price}',
style: TextStyle(
color: Colors.white,
fontFamily: 'Raleway',
fontSize: 22,
fontWeight: FontWeight.w900),
),
),
Padding(
padding: const EdgeInsets.only(top: 25, right: 18),
child: ClipOval(
child: Material(
color: widget.restaurantItem.quantity <= 1
? Colors.grey
: Colors.green, // button color
child: InkWell(
splashColor: Colors.white30, // inkwell color
child: SizedBox(
width: 56,
height: 56,
child: Icon(
Icons.add,
color: Colors.white,
)),
onTap: () {
setState(() {
cartQuantity++;
print(cartQuantity.toString());
});
},
),
),
),
),
],
),
FillButton(
text: 'ADD TO CART',
function: () {
// setState(() {
// cartQuantity++;
// });
},
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(
widget.restaurantItem.isVeg ? 'VEG' : 'NON - VEG',
style: TextStyle(
fontFamily: 'Raleway',
fontSize: 17,
fontWeight: FontWeight.w800,
color:
widget.restaurantItem.isVeg ? Colors.green : Colors.red),
),
),
Container(
height: size.height * 0.3,
color: darkThemeColour,
)
],
),
);
}
}

Your issue is because in your build you are initialiazing your cartQuantity to 0 each time you do a rebuild of the widget. You should initialize it outside the build.
class _ItemBottomSheetState extends State<ItemBottomSheet> {
int cartQuantity = 0;
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final cartItems = Provider.of<Cart>(context).getCartItems;
final index = cartItems.indexWhere((cartItem) =>
cartItem.id == widget.restaurantItem.id &&
cartItem.restaurantId == widget.restaurant.id);
int restQuantity = widget.restaurantItem.quantity;
Now your value will not be always 0 because you initialize it in the construction of the widget. Each time you call setState you do a rebuild and you build gets called.

Related

Flutter GridView Item Selection Color Change (on tap)

I have created a GridView, and the next step I'm trying to achieve is changing the color of the container when it is tapped/ selected. When I try and do it with both Inkwell and GestureDetector, it changes the color of both containers in the row, rather than changing each one individually. I want to have each container change colors when it is tapped, as well as have a check mark appear on the corner:
(1) My Layout
(2) Example of what I want
I'm very new to Flutter, so I know that the way that I've coded my layout is far from optimal. I'm attaching a small chunk of just the GridView portion to show how I created the GridView (basically, I created 6 containers all with varying custom icons and text). Hopefully I'll receive some assistance :).
Updated June 21st:
class SelectionPage extends StatefulWidget {
const SelectionPage({Key? key}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
List <Item>listOfModel = [];
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Being happier and more content in life"));
}
class _SelectionPageState extends State<SelectionPage>{
Color _ContainerColor = Colors.white;
#override
Widget build(BuildContext) {
double _height = MediaQuery.of(context).size.height;
final data = ModalRoute.of(context)!.settings;
late String retrieveString;
if (data.arguments == null)
retrieveString = "empty";
else
retrieveString = data.arguments as String;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.2),
child: Column(
children: <Widget>[
Text('Hello there $data! What all would you like to focus on? You can pick all that apply:',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 12,),
Column(children: [
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: <Widget>[
GestureDetector(
onTap: () {
setState(() {
_ContainerColor = _ContainerColor == Colors.white
? Color(0xffa1d0e6)
: Colors.white;
});
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: _ContainerColor
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp.relationships,
color: Color(0xff31708c),
size: 45,),
),
const SizedBox(height: 4,),
Text('Maintaining healthy relationships',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
),
GestureDetector(
onTap: () {
setState(() {
_ContainerColor = _ContainerColor == Colors.white
? Color(0xffa1d0e6)
: Colors.white;
});
},
child: Container(
padding: const EdgeInsets.all(13.5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp.happy,
color: Color(0xff31708c),
size: 30,),
),
const SizedBox(height: 12,),
Text('Being happier and more content in life',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp.balance,
color: Color(0xff31708c),
size: 40,),
),
const SizedBox(height: 8,),
Text('Maintaining a better work-life balance',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp2.personal_growth,
color: Color(0xff31708c),
size: 35,),
),
const SizedBox(height: 10,),
Text('Personal growth and development',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp2.meditate,
color: Color(0xff31708c),
size: 45,),
),
const SizedBox(height: 4,),
Text('Stress and anxiety management',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
Container(
padding: const EdgeInsets.all(11),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: Colors.white
),
child: Column(
children: [
const Align(alignment: Alignment.topCenter,
child: Icon(MyFlutterApp3.well_rounded,
color: Color(0xff31708c),
size: 37,),
),
const SizedBox(height: 10,),
Text('Mental and emotional well-being',
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
],
),]),
const SizedBox(height: 17,),
ElevatedButton(
onPressed: () {
Navigator.push(context,
PageTransition(
type: PageTransitionType.bottomToTop,
duration: const Duration(milliseconds: 650),
child: const LoginScreen2() // CHANGE THIS AS SOON AS YOU CAN FIGURE SOMETHING OUT
));
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 88,
vertical: 16),
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
)
),
child: Text(
'Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),
),)
],
),
),
);
}
}
Hey you can create a model with 2 variables String title and bool isSelected. If you need you can add icon in item model also -
See below updated code-
class SelectionPage extends StatefulWidget {
const SelectionPage({Key? key}) : super(key: key);
#override
_SelectionPageState createState() => _SelectionPageState();
}
class _SelectionPageState extends State<SelectionPage>{
// Color _ContainerColor = Colors.white;
late String retrieveString;
List <Item>listOfModel = [];
#override
void initState() {
final data = ModalRoute.of(context)!.settings;
if (data.arguments == null) {
retrieveString = "empty";
} else {
retrieveString = data.arguments as String;
}
listOfModel.add(Item(title: "Maintaining healthy relationships"));
listOfModel.add(Item(title: "Being happier and more content in life"));
super.initState();
}
#override
Widget build(BuildContext context) {
double _height = MediaQuery.of(context).size.height;
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: const Color(0xff31708c),
body: Padding(
padding: EdgeInsets.only(
left: 30,
right: 30,
top: _height * 0.2),
child: Column(
children: <Widget>[
Text('Hello there $data! What all would you like to focus on? You can pick all that apply:',
style: GoogleFonts.montserrat(
color: Colors.white70,
fontSize: 19,
fontWeight: FontWeight.w600
),
textAlign: TextAlign.center,),
const SizedBox(height: 12,),
GridView.count(
primary: true,
shrinkWrap: true,
padding: const EdgeInsets.all(10),
childAspectRatio: 1.15,
crossAxisCount: 2,
crossAxisSpacing: 25,
mainAxisSpacing: 25,
children: [
gridItem(listOfModel[0],MyFlutterApp.relationships ),
gridItem(listOfModel[1],MyFlutterApp.relationships ),
],
),
const SizedBox(height: 17,),
ElevatedButton(
onPressed: () {
Navigator.push(context,
PageTransition(
type: PageTransitionType.bottomToTop,
duration: const Duration(milliseconds: 650),
child: const LoginScreen2() // CHANGE THIS AS SOON AS YOU CAN FIGURE SOMETHING OUT
));
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 88,
vertical: 16),
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
)
),
child: Text(
'Continue',
style: GoogleFonts.montserrat(
color: const Color.fromARGB(255, 20, 83, 106),
fontSize: 19,
fontWeight: FontWeight.w600
),
),)
],
),
),
);
}
Widget gridItem(Item item, IconData icon){
return GestureDetector(
onTap: () {
setState(() {
item.isSelected = !item.isSelected;
});
},
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(15),
border: Border.all(
color: const Color.fromARGB(255, 20, 83, 106),
width: 2.5),
color: item.isSelected ? const Color(0xffa1d0e6) : Colors.white
),
child: Column(
children: [
Align(alignment: Alignment.topCenter,
child: Icon(
icon,
color: const Color(0xff31708c),
size: 45,
),
),
const SizedBox(height: 4,),
Text(item.title,
style: GoogleFonts.montserrat(
fontSize: 14,
fontWeight: FontWeight.w500,
color: const Color(0xff31708c)
),
textAlign: TextAlign.center,)
],
),
),
);
}
}
class Item{
String title;
bool isSelected;
Item({required this.title, this.isSelected = false});
}

Flutter 'child' and 'duration' parameter aren't defined

I don't understand why in Positioned widget, I get an error that child parameter isn't defined as well as in AnimatedContainer the 'duration' parameter isn't defined.
I checked the official documentation first, but don't know why it's not working.
https://api.flutter.dev/flutter/widgets/Positioned-class.html
https://api.flutter.dev/flutter/widgets/AnimatedContainer-class.html
class _DetailsPageState extends State<DetailsPage> {
var selectedCard = 'WEIGHT';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF7A9BEE),
appBar: AppBar(
leading: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
),
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text('Details',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 18.0,
color: Colors.white)),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.more_horiz),
onPressed: () {},
color: Colors.white,
)
],
),
body: ListView(children: [
Stack(children: [
Container(
height: MediaQuery.of(context).size.height - 82.0,
width: MediaQuery.of(context).size.width,
color: Colors.transparent),
Positioned(
top: 75.0,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(45.0),
topRight: Radius.circular(45.0),
),
color: Colors.white),
height: MediaQuery.of(context).size.height - 100.0,
width: MediaQuery.of(context).size.width)),
Positioned(
top: 30.0,
left: (MediaQuery.of(context).size.width / 2) - 100.0,
child: Hero(
tag: widget.heroTag,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(widget.heroTag),
fit: BoxFit.cover)),
height: 200.0,
width: 200.0))),
Positioned(
top: 250.0,
left: 25.0,
right: 25.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(widget.foodName,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 22.0,
fontWeight: FontWeight.bold)),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(widget.foodPrice,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 20.0,
color: Colors.grey)),
Container(height: 25.0, color: Colors.grey, width: 1.0),
Container(
width: 125.0,
height: 40.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(17.0),
color: Color(0xFF7A9BEE)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
InkWell(
onTap: () {},
child: Container(
height: 25.0,
width: 25.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.0),
color: Color(0xFF7A9BEE)),
child: Center(
child: Icon(
Icons.remove,
color: Colors.white,
size: 20.0,
),
),
),
),
Text('2',
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat',
fontSize: 15.0)),
InkWell(
onTap: () {},
child: Container(
height: 25.0,
width: 25.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.0),
color: Colors.white),
child: Center(
child: Icon(
Icons.add,
color: Color(0xFF7A9BEE),
size: 20.0,
),
),
),
)
],
),
)
],
),
SizedBox(height: 20.0),
Container(
height: 150.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_buildInfoCard('WEIGHT', '300', 'G'),
SizedBox(width: 10.0),
_buildInfoCard('CALORIES', '267', 'CAL'),
SizedBox(width: 10.0),
_buildInfoCard('VITAMINS', 'A, B6', 'VIT'),
SizedBox(width: 10.0),
_buildInfoCard('AVAIL', 'NO', 'AV')
],
)
),
SizedBox(height: 20.0),
Padding(
padding: EdgeInsets.only(bottom:5.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0), bottomLeft: Radius.circular(25.0), bottomRight: Radius.circular(25.0)),
color: Colors.black
),
height: 50.0,
child: Center(
child: Text(
'\$52.00',
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat'
)
),
),
),
)
],
))
])
]));
}
Widget _buildInfoCard(String cardTitle, String info, String unit) {
return InkWell(
onTap: () {
selectCard(cardTitle);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: cardTitle == selectedCard ? Color(0xFF7A9BEE) : Colors.white,
border: Border.all(
color: cardTitle == selectedCard ?
Colors.transparent :
Colors.grey.withOpacity(0.3),
style: BorderStyle.solid,
width: 0.75
),
),
height: 100.0,
width: 100.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 15.0),
child: Text(cardTitle,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12.0,
color:
cardTitle == selectedCard ? Colors.white : Colors.grey.withOpacity(0.7),
)),
),
Padding(
padding: const EdgeInsets.only(left: 15.0, bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(info,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 14.0,
color: cardTitle == selectedCard
? Colors.white
: Colors.black,
fontWeight: FontWeight.bold)),
Text(unit,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12.0,
color: cardTitle == selectedCard
? Colors.white
: Colors.black,
))
],
),
)
]
)
)
);
}
selectCard(cardTitle) {
setState(() {
selectedCard = cardTitle;
});
}
}
Solved, for some reason I didn't have my Flutter SDK path specified:
1.) Go to Settings
2.) Search Flutter
3.) Click Flutter under Languages & Frameworks
4.) Add you Flutter directory to path, in my case C:\flutter
5.) Apply & OK, Restart IDE

Flutter showModalBottomSheet not changing state need to reopen it to see changes

I am showing showModalBottomSheet issue is its not changing the state I need t close the showModalBottomSheet and open it again to see the changes. Here is my code
List sort = [
{'CatID': 0, 'Name': 'Trending'},
{'CatID': 1, 'Name': 'Newest'},
{'CatID': 2, 'Name': 'Lowset Price'},
{'CatID': 3, 'Name': 'Highest Price'},
];
class BrowserCategoryPage2 extends StatefulWidget {
final subCategory;
const BrowserCategoryPage2({Key key, #required this.subCategory})
: super(key: key);
#override
_BrowserCategoryPage2State createState() => _BrowserCategoryPage2State();
}
class _BrowserCategoryPage2State extends State<BrowserCategoryPage2> {
var items = {'Items': []};
int dateindex;
bool showNotAvail = false;
#override
void initState() {
super.initState();
print('browse subcategory');
print(widget.subCategory);
widget.subCategory.forEach((subcategory) {
items['Items'].addAll(subcategory['Items']);
});
print(items);
print('sada');
}
int currentindex = 0;
int sortindex = 0;
#override
Widget build(BuildContext context) {
double Height = MediaQuery.of(context).size.height;
double Width = MediaQuery.of(context).size.width;
return Scaffold(
body: Container(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SideInAnimation(
2,
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 18.0, vertical: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Products',
style: Theme.of(context).textTheme.headline3,
).tr(),
IconButton(
icon: Icon(
FlutterIcons.filter_fea,
color: Theme.of(context).primaryColor,
),
onPressed: () {
OpenFilter(context);
},
),
]),
),
),
),
SizedBox(height: 10.0),
],
),
),
),
);
}
OpenFilter(BuildContext context){
return showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
double Height = MediaQuery.of(context).size.height;
double Width = MediaQuery.of(context).size.width;
final SortWidget = <Widget>[]; // Here we defined a list of widget!
for (int i = 0; i < sort.length; i++) {
SortWidget.add(
GestureDetector(
onTap: () {
setState(() {
// set current index!
sortindex = i;
print(sortindex);
});
},
child: Container(
height: Height * 0.04,
width: Width * 0.2,
decoration: BoxDecoration(
color: sortindex == i ? Color(0xff04385f) : Colors.white,
border: Border.all(
color:
sortindex == i ? Color(0xff04385f) : Colors.grey[500]),
borderRadius: BorderRadius.all(Radius.circular(10))),
child: Center(
child: Text(
sort[i]['Name'],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 9,
color: sortindex == i ? Colors.white : Colors.grey[500],
fontFamily: 'UbuntuRegular'),
)),
),
),
);
}
return Container(
decoration: BoxDecoration(
borderRadius: new BorderRadius.only(
topLeft:
const Radius.circular(10.0),
topRight:
const Radius.circular(10.0))),
child: new Column(
children: [
Container(
width: double.infinity,
height: Height * 0.055,
decoration: BoxDecoration(
color: Color(0xfff7f7f7)),
child: Center(
child: RichText(
text: new TextSpan(
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(
text: 'Sort & ',
style: new TextStyle(
fontSize: 18,
fontFamily:
'UbuntuBold')),
new TextSpan(
text: 'Filter',
style: TextStyle(
fontSize: 18,
fontFamily:
'UbuntuMedium',
)),
],
),
),
),
),
SizedBox(
height: Height * 0.01,
),
Padding(
padding: const EdgeInsets.only(
left: 13, bottom: 13),
child: Align(
alignment: Alignment.centerLeft,
child: RichText(
text: new TextSpan(
// Note: Styles for TextSpans must be explicitly defined.
// Child text spans will inherit styles from parent
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(
text: 'Sort ',
style: new TextStyle(
fontSize: 16,
fontFamily:
'UbuntuBold')),
new TextSpan(
text: 'By',
style: TextStyle(
fontSize: 16,
fontFamily:
'UbuntuMedium',
)),
],
),
),
),
),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
children: SortWidget,
),
Padding(
padding: const EdgeInsets.only(
left: 13, right: 13, top: 13),
child: Divider(
color: Colors.grey,
thickness: 1,
),
),
SizedBox(
height: Height * 0.01,
),
Padding(
padding: const EdgeInsets.only(
left: 10, right: 10, top: 20),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: [
Container(
height: Height * 0.06,
width: Width * 0.57,
decoration: BoxDecoration(
color: Color(0xff04385f),
borderRadius:
BorderRadius.only(
topLeft:
Radius.circular(
12),
topRight:
Radius.circular(
12),
bottomLeft:
Radius.circular(
12),
bottomRight:
Radius.circular(
12)),
),
child: Center(
child: Text(
'Apply Filters',
style: TextStyle(
fontSize: 15,
fontWeight:
FontWeight.bold,
fontFamily:
'UbuntuRegular',
color: Colors.white),
)),
),
Container(
height: Height * 0.06,
width: Width * 0.3,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey),
color: Colors.white,
borderRadius:
BorderRadius.only(
topLeft:
Radius.circular(
12),
topRight:
Radius.circular(
12),
bottomLeft:
Radius.circular(
12),
bottomRight:
Radius.circular(
12)),
),
child: Center(
child: Text(
'Reset',
style: TextStyle(
fontSize: 15,
fontWeight:
FontWeight.bold,
fontFamily:
'UbuntuRegular',
color:
Color(0xff04385f)),
)),
),
],
),
)
],
),
);
});
}
}
You can see I simply change the color of the container on click. It's changing the index of sort index but issue is it's not changing the state. Mean if I close and open the bottom sheet then I can see the changes.
If flutter BottomSheet works as a widget, so bottomSheet has its own state which does not refresh the data when you call setState({}) of parent Class.
For that you need to use StatefulBuilder for refresh the content of bottomSheet like :
await showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return StatefulBuilder(builder: (BuildContext context, StateSetter state) {
return Container();
});
});
Please replace your method with the following solution it will work properly:
OpenFilter(BuildContext context) {
return showModalBottomSheet<void>(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(builder: (BuildContext context, StateSetter setState) {
double Height = MediaQuery.of(context).size.height;
double Width = MediaQuery.of(context).size.width;
final SortWidget = <Widget>[]; // Here we defined a list of widget!
for (int i = 0; i < sort.length; i++) {
SortWidget.add(
GestureDetector(
onTap: () {
setState(() {
// set current index!
sortindex = i;
print(sortindex);
});
},
child: Container(
height: Height * 0.04,
width: Width * 0.2,
decoration: BoxDecoration(
color: sortindex == i ? Color(0xff04385f) : Colors.white,
border: Border.all(color: sortindex == i ? Color(0xff04385f) : Colors.grey[500]),
borderRadius: BorderRadius.all(Radius.circular(10))),
child: Center(
child: Text(
sort[i]['Name'],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 9,
color: sortindex == i ? Colors.white : Colors.grey[500],
fontFamily: 'UbuntuRegular'),
)),
),
),
);
}
return Container(
decoration: BoxDecoration(
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0), topRight: const Radius.circular(10.0))),
child: new Column(
children: [
Container(
width: double.infinity,
height: Height * 0.055,
decoration: BoxDecoration(color: Color(0xfff7f7f7)),
child: Center(
child: RichText(
text: new TextSpan(
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(text: 'Sort & ', style: new TextStyle(fontSize: 18, fontFamily: 'UbuntuBold')),
new TextSpan(
text: 'Filter',
style: TextStyle(
fontSize: 18,
fontFamily: 'UbuntuMedium',
)),
],
),
),
),
),
SizedBox(
height: Height * 0.01,
),
Padding(
padding: const EdgeInsets.only(left: 13, bottom: 13),
child: Align(
alignment: Alignment.centerLeft,
child: RichText(
text: new TextSpan(
// Note: Styles for TextSpans must be explicitly defined.
// Child text spans will inherit styles from parent
style: new TextStyle(
fontSize: 14.0,
color: Colors.black,
),
children: <TextSpan>[
new TextSpan(text: 'Sort ', style: new TextStyle(fontSize: 16, fontFamily: 'UbuntuBold')),
new TextSpan(
text: 'By',
style: TextStyle(
fontSize: 16,
fontFamily: 'UbuntuMedium',
)),
],
),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: SortWidget,
),
Padding(
padding: const EdgeInsets.only(left: 13, right: 13, top: 13),
child: Divider(
color: Colors.grey,
thickness: 1,
),
),
SizedBox(
height: Height * 0.01,
),
Padding(
padding: const EdgeInsets.only(left: 10, right: 10, top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: Height * 0.06,
width: Width * 0.57,
decoration: BoxDecoration(
color: Color(0xff04385f),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12)),
),
child: Center(
child: Text(
'Apply Filters',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
fontFamily: 'UbuntuRegular',
color: Colors.white),
)),
),
Container(
height: Height * 0.06,
width: Width * 0.3,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12)),
),
child: Center(
child: Text(
'Reset',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
fontFamily: 'UbuntuRegular',
color: Color(0xff04385f)),
)),
),
],
),
)
],
),
);
});
});
}
Flutter is amazing at rebuilding its widgets as little as possible. So if there are any constant widgets/values, it won't rebuild them. This also applies to bottom sheets.
If you would like to have your bottom sheet update with hot restart you can create a stateful widget within your bottomsheet and then it will update.
Here is an example of such:
class MyBottomSheet extends StatefulWidget {
const MyBottomSheet({
Key key,
}) : super(key: key);
Future<T> show<T>(BuildContext context) {
return showModalBottomSheet<T>(
context: context,
isDismissible: true,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => return this,
);
}
#override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
height: 310,
);
}
}
and to access the bottom sheet you can call it via MyBottomSheet().show(context);
to see the changes made to your showModalBottomSheet with Hot Reload just extract the Widget from the return value.
Example:
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: (){
showModalBottomSheet(
context: context, builder: (context){
return AddNoteBottomSheet();
});
}, child: Text('+', style: TextStyle(fontSize: 30.0),),),
body: NotesViewBody(),
);
}
now you ca see all changes made on AddNoteBottomSheet() widget with hot reload reload.

ListView isn't scrolling in Flutter

ListView is not working here, Firstly instead of padding I used Positioned() but there is a similar issue on github and there I got to know that scrollable widget shouldn't be placed inside Positioned() so i replaced it with Padding(), but got no success.
here is my code
import 'package:flutter/material.dart';
import 'package:cpblog/webview.dart';
import 'package:flutter/rendering.dart';
class DetailsPage extends StatefulWidget {
final heroTag;
final foodName;
final url;
final text;
DetailsPage({this.heroTag, this.foodName,this.url,this.text});
#override
_DetailsPageState createState() => _DetailsPageState();
}
class _DetailsPageState extends State<DetailsPage> {
var selectedCard = 'WEIGHT';
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF7A9BEE),
appBar: AppBar(
leading: IconButton(
onPressed: () {
Navigator.of(context).pop();
},
icon: Icon(Icons.arrow_back_ios),
color: Colors.white,
),
backgroundColor: Colors.transparent,
elevation: 0.0,
title: Text('Here You Go!!',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 18.0,
color: Colors.white)),
centerTitle: true,
actions: <Widget>[
IconButton(
icon: Icon(Icons.more_horiz),
onPressed: () {},
color: Colors.white,
)
],
),
body: ListView(children: [
Stack(children: [
Container(
height: MediaQuery.of(context).size.height - 82.0,
width: MediaQuery.of(context).size.width,
color: Colors.transparent),
Padding(
padding: const EdgeInsets.only(top: 75.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(45.0),
topRight: Radius.circular(45.0),
),
color: Colors.white),
height: MediaQuery.of(context).size.height - 100.0,
width: MediaQuery.of(context).size.width),
),
Padding(
padding: EdgeInsets.only(top: 30.0,
left: (MediaQuery.of(context).size.width / 2) - 100.0,),
child: Hero(
tag: widget.heroTag,
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(widget.heroTag),
fit: BoxFit.cover)),
height: 200.0,
width: 200.0)),
),
Padding(
padding: const EdgeInsets.only(top:250.0,right:25.0,left: 25.0),
child: ListView(
shrinkWrap: true,
children: <Widget>[
Text(widget.foodName,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 22.0,
fontWeight: FontWeight.bold)),
SizedBox(height: 20.0),
Text(widget.text,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 20.0,
)),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: 125.0,
height: 40.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(17.0),
color: Color(0xFF7A9BEE)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => WebView(widget.url, widget.foodName)));
},
child:Text('View More',
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat',
fontSize: 15.0)),
)
],
),
)
],
),
SizedBox(height: 20.0),
Container(
height: 150.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_buildInfoCard('WEIGHT', '300', 'G'),
SizedBox(width: 10.0),
_buildInfoCard('CALORIES', '267', 'CAL'),
SizedBox(width: 10.0),
_buildInfoCard('VITAMINS', 'A, B6', 'VIT'),
SizedBox(width: 10.0),
_buildInfoCard('AVAIL', 'NO', 'AV')
],
)
),
SizedBox(height: 20.0),
Padding(
padding: EdgeInsets.only(bottom:5.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(topLeft: Radius.circular(10.0), topRight: Radius.circular(10.0), bottomLeft: Radius.circular(25.0), bottomRight: Radius.circular(25.0)),
color: Colors.black
),
height: 50.0,
child:
InkWell(
onTap: () {
Navigator.pop(context);
},
child: Center(
child: Text(
'Back',
style: TextStyle(
color: Colors.white,
fontFamily: 'Montserrat'
)
),
),
)
),
)
],
),
)
])
]));
}
Widget _buildInfoCard(String cardTitle, String info, String unit) {
return InkWell(
onTap: () {
selectCard(cardTitle);
},
child: AnimatedContainer(
duration: Duration(milliseconds: 500),
curve: Curves.easeIn,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: cardTitle == selectedCard ? Color(0xFF7A9BEE) : Colors.white,
border: Border.all(
color: cardTitle == selectedCard ?
Colors.transparent :
Colors.grey.withOpacity(0.3),
style: BorderStyle.solid,
width: 0.75
),
),
height: 100.0,
width: 100.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 15.0),
child: Text(cardTitle,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12.0,
color:
cardTitle == selectedCard ? Colors.white : Colors.grey.withOpacity(0.7),
)),
),
Padding(
padding: const EdgeInsets.only(left: 15.0, bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(info,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 14.0,
color: cardTitle == selectedCard
? Colors.white
: Colors.black,
fontWeight: FontWeight.bold)),
Text(unit,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12.0,
color: cardTitle == selectedCard
? Colors.white
: Colors.black,
))
],
),
)
]
)
)
);
}
selectCard(cardTitle) {
setState(() {
selectedCard = cardTitle;
});
}
}
I tried physics, listView.builder(),but everytime I get the same result.
Thank you in advance!!!!
Surround you ListView with Expanded widget.
You can't have a scrollable widget inside another scrollable widget without setting a proper height for the inner one. Or use ConstrainedBox

The method 'call' was called on null. Receiver: null Tried calling: call(navegacion_bloques)

give me some of your time please, I have this error "mainMenu().onMenuTap()" and I don't know how to fix it.
The following NoSuchMethodError was thrown while handling a gesture:
The method 'call' was called on null.
Receiver: null
Tried calling: call(navegacion_bloques)
in my StatelessWidget class it worked fine, but I passed everything to a Statefulwidget and I can't use this function.
My code is this:
import 'package:flutter/material.dart';
import 'package:example/bloc/navegacion_bloques/navegacion_bloques.dart';
import 'package:example/ui/pages/productos/categorias.dart';
import 'package:example/ui/pages/productos/productdetails.dart';
class mainMenu extends StatefulWidget with NavigationStates{
final Function onMenuTap;
const mainMenu({Key key, this.onMenuTap}) : super(key: key);
#override
_mainMenu createState() => _mainMenu();
}
class _mainMenu extends State<mainMenu>
{
final categorias= allCategories;
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: ClampingScrollPhysics(),
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.deepPurple[300], Colors.deepPurpleAccent]
),
borderRadius:BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
topLeft: Radius.circular(20),
topRight: Radius.circular(20)),
),
padding: const EdgeInsets.only(left: 16.0, right: 16.0, top: 40),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children:[
InkWell(child: Icon(Icons.menu,color: Colors.grey[300],),
onTap:(){
mainMenu().onMenuTap();
},),
Text(
"",
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontFamily: 'BalooMedium'),
),
InkWell(child: Icon(Icons.shopping_cart,color: Colors.grey[300],),
onTap:(){
mainMenu().onMenuTap();
},),
],
),
SizedBox(
height: 5,
),
Container(
padding: const EdgeInsets.only(left: 10.0,right: 10.0),
child: Column(
children: <Widget>[
Row(
children:[
Text(
"store",
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontFamily: 'BalooMedium'),
)
],
),
Row(
children:[
Text(
"hi",
style: TextStyle(
color: Colors.white,
fontSize: 15,
fontFamily: 'BalooMedium'),
)
],
),
Row(
children:[
Text(
"There!",
style: TextStyle(
color: Colors.white,
fontSize: 15,
fontFamily: 'BalooMedium'),
)
],
)
],
),
),
SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.only(left: 10.0,right: 10.0),
child: TextField(
style: TextStyle(
fontFamily: 'BalooMedium',
fontSize: 18.0,
color: Colors.grey[200],
),
decoration: InputDecoration(
prefixIcon: IconButton(icon: Icon(Icons.search,color: Colors.grey[200],),onPressed: null,),
hintText: '¿Qué Necesitas?',
hintStyle:TextStyle(
fontFamily: 'BalooMedium',
fontSize: 18.0,
color: Colors.grey[200],
),
suffixIcon: IconButton(icon: Icon(Icons.filter_list,color: Colors.grey[200],),onPressed: null,),
),
),
),
],
),
),
);
}
buildCategoriasGrid(Categorias categorias){
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
//builder: (context) => productdetails(selectedInstructor: categorias)
));
},
child: Padding(
padding: EdgeInsets.all(5.0),
child: Stack(
children: <Widget>[
Container(
height: 150.0, width: 100.0, color: Colors.transparent),
Positioned(
left: 30.0,
top: 65.0,
child: Container(
height: 30.0,
width: 40.0,
decoration: BoxDecoration(boxShadow: [
BoxShadow(
blurRadius: 7.0,
color: Colors.grey.withOpacity(0.75),
offset: Offset(5, 25),
spreadRadius: 12.0)
]))),
Positioned(
left: 12.0,
top: 15.0,
child: Hero(
tag: categorias.productImg,
child: Container(
height: 110.0,
width: 85.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(7.0),
image: DecorationImage(
image: AssetImage(categorias.productImg),
fit: BoxFit.cover))))),
Positioned(
left: 22.0,
top: 138.0,
child: Column(
children: <Widget>[
Text(categorias.productName,
style: TextStyle(
fontFamily: 'BalooMedium',
fontSize: 10.0,
color: Colors.grey[200],
),),
Row(children: [
Icon(
Icons.star,
color: Colors.grey.withOpacity(0.5),
size: 15.0,
),
SizedBox(width: 3.0),
Text(categorias.productRating,
style: TextStyle(
fontFamily: 'BalooMedium',
fontSize: 10.0,
color: Colors.grey[200],
),)
])
],
))
],
)));
}
}
Replace
mainMenu().onMenuTap()
with
widget.onMenuTap()
Calling mainMenu() just creates a new instance of the mainMenu class without the corresponding information so onMenuTap() is null.
The widget property is the "State object's configuration [which] is the corresponding StatefulWidget instance." Source
So the widget property, when used in the State object, contains the information you need so onMenuTap() would contain the supplied argument.