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.
Related
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});
}
I'm trying to create a container in which I can perform two gesture: onTapDown and onTapUp. I want to decrease the dimension of my container when I perform onTapDown.
What I want is something like that:
https://i.imgur.com/7hW2Cn1.gifv
The problem is that if I work with AnimatedController I need to resize also the children and it's a mess.
I also looked to the flutter_bounce library but what I want is not something based on a duration. If the user keep pressed the container maintains the state of pressed.
class CustomContainerState extends State<CustomContainer> {
double width = 90.w;
double height = 35.h;
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Center(
child: AnimatedContainer(
duration: Duration(milliseconds: 200),
margin: EdgeInsets.only(left: 5.w, right: 5.w),
width: width,
height: height,
child: Column(
children: [
Container(
width: 90.w,
height: 25.h,
decoration: BoxDecoration(
color: green400,
borderRadius: BorderRadius.only(topLeft: Radius.circular(5.w), topRight: Radius.circular(5.w)),
),
),
Container(
margin: EdgeInsets.only(left: 5.w, right: 5.w, top: 1.h, bottom: 1.h),
width: 90.w,
height: 8.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(bottomLeft: Radius.circular(5.w), bottomRight: Radius.circular(5.w)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
"Ratings",
style: TextStyle(
fontFamily: "SanFrancisco",
fontSize: 10.sp,
fontWeight: FontWeight.w400,
overflow: TextOverflow.ellipsis,
),
),
Text(
"Title",
style: TextStyle(
fontFamily: "SanFrancisco",
fontSize: 12.sp,
fontWeight: FontWeight.w600,
overflow: TextOverflow.ellipsis,
),
),
Text(
"Description",
style: TextStyle(
fontFamily: "SanFrancisco",
fontSize: 10.sp,
fontWeight: FontWeight.w400,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
],
),
),
),
onTapDown: (tapDownDetails) {
setState(() {
width = 85.w;
height = 30.h;
});
},
onTapUp: (TapUpDetails) {
setState(() {
width = 90.w;
height = 35.h;
});
},
);
}
}
The problem so is how to decrease only the parent container that automatically decrease also the children? Because I can use multiple AnimatedContainer also for the children but the problem is that the text is not animated.
Have you tried with scale instead of changing width and height? Something like this:
class CustomContainerState extends State<CustomContainer> {
double width = 90;
double height = 350;
double scale = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: GestureDetector(
child: Center(
child: AnimatedContainer(
transform: Matrix4.identity()..scale(scale),
color: Colors.green,
duration: Duration(milliseconds: 200),
margin: EdgeInsets.only(left: 5, right: 5),
width: width,
height: height,
child: Column(
children: [
Container(
width: 90,
height: 25,
decoration: BoxDecoration(
// color: green400,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5)),
),
),
Container(
margin: EdgeInsets.only(
left: 5, right: 5, top: 1, bottom: 1),
width: 90,
height: 80,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(5),
bottomRight: Radius.circular(5)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
"Ratings",
style: TextStyle(
fontFamily: "SanFrancisco",
fontSize: 10,
fontWeight: FontWeight.w400,
overflow: TextOverflow.ellipsis,
),
),
Text(
"Title",
style: TextStyle(
fontFamily: "SanFrancisco",
fontSize: 12,
fontWeight: FontWeight.w600,
overflow: TextOverflow.ellipsis,
),
),
Text(
"Description",
style: TextStyle(
fontFamily: "SanFrancisco",
fontSize: 10,
fontWeight: FontWeight.w400,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
],
),
),
),
onTapDown: (tapDownDetails) {
setState(() {
// width = 85;
// height = 300;
scale = .8;
});
},
onTapUp: (TapUpDetails) {
setState(() {
// width = 90;
// height = 350;
scale = 1;
});
},
),
),
);
}
}
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.
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
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.