Ripple effect appears under custem listview item on click in Flutter - flutter

I have tried many solutions from this platform and others too but my problem remains the same. I have done this before and successfully ripple the listview item in another custom listview. But this time i am not getting any clue where i am lacking. The previous solution make things more messy if try this time. Ripple is appearing under listview item what i want is to only listview item do ripples.
class Dashboard extends StatefulWidget {
#override
_DashboardState createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
// Map<String, dynamic> args;
List<DashboardItem> lst = [
DashboardItem(
img: 'assets/sales.png', name: 'Sales', subtitle: 'Your daily sales'),
DashboardItem(
img: 'assets/order.png', name: 'Orders', subtitle: 'Your new orders'),
DashboardItem(
img: 'assets/report.png',
name: 'Reports',
subtitle: 'Your daily reports'),
DashboardItem(
img: 'assets/setting.png',
name: 'Setting',
subtitle: 'Application setting'),
DashboardItem(
img: 'assets/register.png',
name: 'Register',
subtitle: 'Close your register'),
DashboardItem(
img: 'assets/logout.png', name: 'Logout', subtitle: 'You can rest')
];
#override
Widget build(BuildContext context) {
// args = ModalRoute.of(context).settings.arguments;
// print('Dashboard : ${args['regId']}');
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
elevation: 0.0,
title: Text('My Dashboard'),
centerTitle: true,
),
body: LayoutBuilder(
builder: (context, constraints){
if(constraints.maxWidth < 600){
return ListView.builder(
itemCount: lst.length,
shrinkWrap: true,
itemBuilder: (context, position){
return Container(
padding: position == lst.length ? const EdgeInsets.only(top:16.0) : const EdgeInsets.only(top:16.0, bottom: 16.0),
child: InkWell(
child: DashboardCard(lst[position]),
onTap: (){
Toast.show('In List', context);
},
),
);
},
);
}
else{
return GridView.builder(
itemCount: lst.length,
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
itemBuilder: (context, position){
return InkWell(
child: DashboardCard(lst[position]),
onTap: (){
Toast.show('In Grid', context);
},
);
},
);
}
},
),
);
}
}
DashboardCard Class
class DashboardCard extends StatelessWidget {
final DashboardItem _dashboardItem;
const DashboardCard(this._dashboardItem);
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 230,
width: 280,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 10.0,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(
image: AssetImage(_dashboardItem.img),
fit: BoxFit.contain,
width: 80,
height: 80,
),
SizedBox(height: 20,),
Text(
_dashboardItem.name,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
fontFamily: 'Ubuntu',
letterSpacing: 2.0,
color: Colors.redAccent,
),
),
Padding(
padding: const EdgeInsets.all(3.0),
child: Text(
_dashboardItem.subtitle,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.normal,
letterSpacing: 2.0,
color: Colors.grey,
),
),
),
],
),
),
),
),
);
}
}

The issue is with the Center widget in your DashboardCard:
You can fix it wrapping your DashboardCard Container widget in an InkWell widget and pass a onTap parameter to the DashboardCard constructor:
class DashboardCard extends StatelessWidget {
final DashboardItem _dashboardItem;
final VoidCallback onTap;
const DashboardCard(
this._dashboardItem, {
this.onTap,
});
#override
Widget build(BuildContext context) {
return Center(
child: InkWell(
onTap: onTap,
child: Container(
height: 230,
width: 280,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 10.0,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image(
image: AssetImage(_dashboardItem.img),
fit: BoxFit.contain,
width: 80,
height: 80,
),
SizedBox(
height: 20,
),
Text(
_dashboardItem.name,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
fontFamily: 'Ubuntu',
letterSpacing: 2.0,
color: Colors.redAccent,
),
),
Padding(
padding: const EdgeInsets.all(3.0),
child: Text(
_dashboardItem.subtitle,
maxLines: 2,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.normal,
letterSpacing: 2.0,
color: Colors.grey,
),
),
),
],
),
),
),
),
),
);
}
}
The use it in other places like:
DashboardCard(
lst[position],
onTap: () {
Toast.show('In List', context);
},
),

Related

How do i correctly initialise a variable from a stateful widget to another widget in flutter and maintain state?

I have two widgets
JobsHeaderWidget
JobsView
JobsHeaderWidget is a stateful widget where i code all the logic and initialise int current = 0; in the state. In this same file, i have another class named CategoriesBuilder where i use switch cases to make sure at each switch case a different container is returned. ( a switch case for each tab )
This switch cases is now responsible for switching containers depending on the tab bar selected as seen in this image:
I will also drop the code snippet of the JobsHeaderWidget for better clarifications.
The problem is - when i use this CategoriesBuilder in same widget as the 'JobsHeaderWidget' it works.
But i don't want to use it in same widget cos of the logic of my design. I want to be able to use this builder in JobsView widget which is another dart file and it doesn't work maybe because of wrong approach.
I tried converting the JobsView to a stateful widget and initialising 'int current = 0;' but it doesn't work.
I also tried making int current = 0; global var, it worked but the state doesn't change when i select individual tab bars. ( I mean my switch cases don't seem to work ).
I have gone round stackoverflow for answers before asking this but can't find a solution.
Snippets of each widgets below.
JobsHeaderWidget
class JobsHeaderWidget extends StatefulWidget {
const JobsHeaderWidget({
Key key,
}) : super(key: key);
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
ValueChanged<int> onChange;
int current = 0;
List<DropdownMenuItem<String>> get dropdownItems {
List<DropdownMenuItem<String>> menuItems = [
DropdownMenuItem(
child: Text(
"Today",
),
value: "Today"),
];
return menuItems;
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jobs',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w600),
),
Row(
children: [
Text(
'View Insights ',
style: GoogleFonts.poppins(
color: Color(0xff3498DB),
fontSize: 12,
fontWeight: FontWeight.w500),
),
Icon(
Icons.arrow_forward_ios,
color: Color(0xff3498DB),
size: 12,
),
],
),
SizedBox(
height: 10,
),
filterJobs(),
],
),
),
);
}
Widget filterJobs() {
String selectedValue = "Today";
return Column(
children: [
Container(
constraints: const BoxConstraints(maxWidth: 600, maxHeight: 100),
width: double.infinity,
child: IntrinsicWidth(
child: FittedBox(
fit: BoxFit.fitWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < items.length; i++) ...[
GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 14.0, right: 14.0, top: 4, bottom: 4),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(50),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 15,
fontWeight: FontWeight.w500,
color:
current == i ? Colors.white : Colors.grey),
),
),
),
),
]
],
),
),
),
),
Divider(
color: Color(0xff34495E).withOpacity(0.2),
),
Row(
children: [
Text(
'All Jobs',
style:
GoogleFonts.poppins(fontSize: 9, fontWeight: FontWeight.w400),
),
SizedBox(
width: 5,
),
Text(
' * This Week',
style:
GoogleFonts.poppins(fontSize: 9, fontWeight: FontWeight.w400),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'25',
style: GoogleFonts.poppins(
fontSize: 20, fontWeight: FontWeight.w600),
),
Container(
height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xffF4F4F4)),
child: Padding(
padding: const EdgeInsets.only(
left: 8.0,
),
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xff34495E),
borderRadius: BorderRadius.circular(2)),
child: Icon(
Icons.tune,
size: 15,
color: Colors.white,
),
),
SizedBox(
width: 5,
),
DropdownMenuItem(
child: DropdownButtonHideUnderline(
child: Container(
child: DropdownButton(
isDense: true,
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color(0xff34495E),
),
onChanged: (value) {},
items: dropdownItems,
value: selectedValue,
),
),
),
),
],
),
),
),
],
),
//If i uncomment this line and use the category builder here, it works fine! CategoriesBuilder(current: current)
],
);
}
}
class CategoriesBuilder extends StatelessWidget {
const CategoriesBuilder({
Key key,
#required this.current,
}) : super(key: key);
final int current;
#override
Widget build(BuildContext context) {
return Builder(
builder: (context) {
switch (current) {
case 0:
return AllJobsListView();
case 1:
return CriticalJobsListView();
case 2:
return OpenJobsListView();
case 3:
return ClosedJobsListView();
case 4:
return OverdueJobsListView();
default:
return SizedBox.shrink();
}
},
);
}
}
JobsView
class JobsView extends StatefulWidget {
const JobsView({
Key key,
}) : super(key: key);
#override
State<JobsView> createState() => _JobsViewState();
}
class _JobsViewState extends State<JobsView> {
int current = 0;
#override
Widget build(BuildContext context) {
final controller = Get.put(EServicesController());
return Scaffold(
// floatingActionButton: new FloatingActionButton(
// child: new Icon(Icons.add, size: 32, color: Get.theme.primaryColor),
// onPressed: () => {Get.offAndToNamed(Routes.E_SERVICE_FORM)},
// backgroundColor: Get.theme.colorScheme.secondary,
// ),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
body: RefreshIndicator(
onRefresh: () async {
Get.find<LaravelApiClient>().forceRefresh();
controller.refreshEServices(showMessage: true);
Get.find<LaravelApiClient>().unForceRefresh();
},
child: CustomScrollView(
controller: controller.scrollController,
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: false,
slivers: <Widget>[
SliverAppBar(
backgroundColor: Color(0xffFFFFFF),
expandedHeight: MediaQuery.of(context).size.height * 0.4,
elevation: 0.5,
primary: true,
pinned: false,
floating: false,
//iconTheme: IconThemeData(color: Get.theme.primaryColor),
// title: Text(
// "Jobs".tr,
// style: Get.textTheme.headline6
// .merge(TextStyle(color: Get.theme.primaryColor)),
// ),
centerTitle: false,
automaticallyImplyLeading: false,
// leading: new IconButton(
// icon: new Icon(Icons.arrow_back_ios,
// color: Get.theme.primaryColor),
// onPressed: () => {Get.back()},
// ),
actions: [
SearchButtonWidget(),
],
//bottom: HomeSearchBarWidget(),
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: JobsHeaderWidget(),
)),
SliverToBoxAdapter(
child: Wrap(
children: [
//ServicesListWidget(),
// The state doesnt change here for some reasosns CategoriesBuilder(current: current)
],
),
),
],
),
),
);
}
}
Try this: keep your 'int current' within _JobsViewState as you have in your code.
When you call your JobsHeaderWidget , pass the function it will use to update the the value of the current variable; and rebuild the state from here.
Something like this:
class JobsHeaderWidget extends StatefulWidget {
final Function changeCurrentValue(int newValue);
const JobsHeaderWidget({
this.changeCurrentValue,
Key key,
}) : super(key: key);
#override
State<JobsHeaderWidget> createState() => _JobsHeaderWidgetState();
}
class _JobsHeaderWidgetState extends State<JobsHeaderWidget> {
#override
Widget build(BuildContext context) {
// Somewhere inside build, instead calling setState()
// call the function you passed to the widget
GestureDetector(
onTap: () {
changeCurrentValue(i);
},
)
}
}
class _JobsViewState extends State<JobsView> {
int current = 0;
void changeCurrentValue(int newValue) {
setState(() {
current = newValue;
});
}
#override
Widget build(BuildContext context) {
//somewhere inside build
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: JobsHeaderWidget(changeCurrentValue: changeCurrentValue),
)),
}
}
After hours and even sleeping overnight on this question i came up with a work-around that works. (minor refactoring)
This was my approach :
Convert my JobsView widget to a stateful widget and put all my controllers in place.
Copied all my variables from JobHeaderWidget and put it in the state of my JobsView widget.
Instead of returning a widget in the title of my sliver app as thus :
flexibleSpace: FlexibleSpaceBar( collapseMode: CollapseMode.parallax, title: JobsHeaderWidget(), )),
I copied all of my code from the widget tree from JobsHeaderWidget and put converted to a method and replaced it in my title.
My builder CategoryBuilder was put in a separate then imported as i used it in my SliverAppAdapter .
Of cos i got rid of the unnecessary dart file JobsHeaderWidget.
FULL CODE BELOW
class JobsView extends StatefulWidget {
#override
State<JobsView> createState() => _JobsViewState();
}
class _JobsViewState extends State<JobsView> {
List<String> items = [
"All",
"Critical",
"Open",
"Closed",
"Overdue",
];
int current = 0;
List<DropdownMenuItem<String>> get dropdownItems {
List<DropdownMenuItem<String>> menuItems = [
DropdownMenuItem(
child: Text(
"Today",
),
value: "Today"),
];
return menuItems;
}
#override
Widget build(BuildContext context) {
final controller = Get.put(EServicesController());
return Scaffold(
// floatingActionButton: new FloatingActionButton(
// child: new Icon(Icons.add, size: 32, color: Get.theme.primaryColor),
// onPressed: () => {Get.offAndToNamed(Routes.E_SERVICE_FORM)},
// backgroundColor: Get.theme.colorScheme.secondary,
// ),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
body: RefreshIndicator(
onRefresh: () async {
Get.find<LaravelApiClient>().forceRefresh();
controller.refreshEServices(showMessage: true);
Get.find<LaravelApiClient>().unForceRefresh();
},
child: CustomScrollView(
controller: controller.scrollController,
physics: AlwaysScrollableScrollPhysics(),
shrinkWrap: false,
slivers: <Widget>[
SliverAppBar(
backgroundColor: Color(0xffFFFFFF),
expandedHeight: MediaQuery.of(context).size.height * 0.4,
elevation: 0.5,
primary: true,
pinned: false,
floating: false,
//iconTheme: IconThemeData(color: Get.theme.primaryColor),
// title: Text(
// "Jobs".tr,
// style: Get.textTheme.headline6
// .merge(TextStyle(color: Get.theme.primaryColor)),
// ),
centerTitle: false,
automaticallyImplyLeading: false,
// leading: new IconButton(
// icon: new Icon(Icons.arrow_back_ios,
// color: Get.theme.primaryColor),
// onPressed: () => {Get.back()},
// ),
actions: [
SearchButtonWidget(),
],
//bottom: HomeSearchBarWidget(),
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: mainHeader(),
)),
SliverToBoxAdapter(
child: Wrap(
children: [
//ServicesListWidget(),
CategoriesBuilder(current: current)
],
),
),
],
),
),
);
}
Padding mainHeader() {
return Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jobs',
style: GoogleFonts.poppins(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.w600),
),
Row(
children: [
Text(
'View Insights ',
style: GoogleFonts.poppins(
color: Color(0xff3498DB),
fontSize: 12,
fontWeight: FontWeight.w500),
),
Icon(
Icons.arrow_forward_ios,
color: Color(0xff3498DB),
size: 12,
),
],
),
SizedBox(
height: 10,
),
() {
String selectedValue = "Today";
return Column(
children: [
Container(
constraints:
const BoxConstraints(maxWidth: 600, maxHeight: 100),
width: double.infinity,
child: IntrinsicWidth(
child: FittedBox(
fit: BoxFit.fitWidth,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
for (int i = 0; i < items.length; i++) ...[
GestureDetector(
onTap: () {
setState(() {
current = i;
});
},
child: AnimatedContainer(
height: 40,
duration: const Duration(milliseconds: 300),
margin: const EdgeInsets.all(5),
padding: const EdgeInsets.only(
left: 14.0,
right: 14.0,
top: 4,
bottom: 4),
decoration: BoxDecoration(
color: current == i
? const Color(0xff34495E)
: const Color(0xffF5F5F5),
borderRadius: BorderRadius.circular(50),
),
child: Center(
child: Text(
items[i],
style: GoogleFonts.poppins(
fontSize: 15,
fontWeight: FontWeight.w500,
color: current == i
? Colors.white
: Colors.grey),
),
),
),
),
]
],
),
),
),
),
Divider(
color: Color(0xff34495E).withOpacity(0.2),
),
Row(
children: [
Text(
'All Jobs',
style: GoogleFonts.poppins(
fontSize: 9, fontWeight: FontWeight.w400),
),
SizedBox(
width: 5,
),
Text(
' * This Week',
style: GoogleFonts.poppins(
fontSize: 9, fontWeight: FontWeight.w400),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'25',
style: GoogleFonts.poppins(
fontSize: 20, fontWeight: FontWeight.w600),
),
Container(
height: 30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2),
color: Color(0xffF4F4F4)),
child: Padding(
padding: const EdgeInsets.only(
left: 8.0,
),
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: Color(0xff34495E),
borderRadius: BorderRadius.circular(2)),
child: Icon(
Icons.tune,
size: 15,
color: Colors.white,
),
),
SizedBox(
width: 5,
),
DropdownMenuItem(
child: DropdownButtonHideUnderline(
child: Container(
child: DropdownButton(
isDense: true,
style: GoogleFonts.poppins(
fontSize: 10,
fontWeight: FontWeight.w500,
color: Color(0xff34495E),
),
onChanged: (value) {},
items: dropdownItems,
value: selectedValue,
),
),
),
),
],
),
),
),
],
),
//CategoriesBuilder(current: current)
],
);
}(),
],
),
),
);
}
}

How can I fix the renderflex overflow of a card in Flutter?

How can I fix the RenderFlex overflowed pixel in my card Flutter? I cant seem to find a tutorial regarding this kind of problem. All of the tutorials in StackOverflow teach you to use the listview and SingleChildScrollView but that is not the case for me. The error shows in the card itself and I don't want the card to be using a singlechildscrollview.
I already tried fixing it by lowering the height and width but I will still need a proper tutorial that can help me fix this kind of issues.
This is the card.dart for the application
import 'package:flutter/material.dart';
class ListViewCard extends StatelessWidget {
final String title;
final void Function()? onTap;
final String imageOfPlant; //Change to String
const ListViewCard({
super.key,
required this.title,
required this.onTap,
required this.imageOfPlant,
});
#override
Widget build(BuildContext context) {
return Card(
color: const Color.fromARGB(255, 75, 175, 78),
elevation: 1,
margin: const EdgeInsets.all(8),
semanticContainer: true,
clipBehavior: Clip.antiAliasWithSaveLayer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
child: InkWell(
splashColor: Colors.lightGreenAccent.withAlpha(30),
onTap: onTap,
//sizedBox of the card
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//image of the card
Image.asset(
imageOfPlant,
height: 200,
width: 150,
fit: BoxFit.cover,
),
SizedBox(
height: 50,
width: 150,
child: Center(
child: Text(
title,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 19,
fontFamily: 'RobotoMedium',
color: Color(0xffeeeeee)), // textstyle
),
),
), //text //SizedBox
], // <widget>[]
), // column
), //inkwell
); // card
}
}
This is the home.dart where the card will be called.
import 'package:flutter/material.dart';
import 'package:picleaf/nav_pages/plant.dart';
import '../widgets/card.dart';
class homePage extends StatefulWidget {
const homePage({super.key});
#override
State<homePage> createState() => _HomePageState();
}
List<String> plants = [
"Bell Pepper",
"Cassava",
"Grape",
"Potato",
"Strawberry",
"Tomato",
];
class CustomSearchDelegate extends SearchDelegate {
// Demo list to show querying
CustomSearchDelegate({String hinttext = "Search plants here"})
: super(searchFieldLabel: hinttext);
// first overwrite to
// clear the search text
#override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = '';
},
icon: const Icon(Icons.clear),
),
];
}
// second overwrite to pop out of search menu
#override
Widget? buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
close(context, null);
},
icon: const Icon(Icons.arrow_back),
);
}
// third overwrite to show query result
#override
Widget buildResults(BuildContext context) {
List<String> matchQuery = [];
for (var fruit in plants) {
if (fruit.toLowerCase().contains(query.toLowerCase())) {
matchQuery.add(fruit);
}
}
return ListView.builder(
itemCount: matchQuery.length,
itemBuilder: (context, index) {
var result = matchQuery[index];
return ListTile(
title: Text(
result,
style: const TextStyle(fontFamily: 'RobotoMedium'),
),
);
},
);
}
// last overwrite to show the
// querying process at the runtime
#override
Widget buildSuggestions(BuildContext context) {
List<String> matchQuery = [];
for (var fruit in plants) {
if (fruit.toLowerCase().contains(query.toLowerCase())) {
matchQuery.add(fruit);
}
}
return ListView.builder(
itemCount: matchQuery.length,
itemBuilder: (context, index) {
var result = matchQuery[index];
return ListTile(
title: Text(
result,
style: const TextStyle(fontFamily: 'RobotoMedium'),
),
);
},
);
}
}
class _HomePageState extends State<homePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text(
"PicLeaf",
style: TextStyle(
color: Color.fromRGBO(102, 204, 102, 1.0),
fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
shadowColor: const Color.fromARGB(255, 95, 94, 94),
actions: [
IconButton(
onPressed: () {
// method to show the search bar
showSearch(
context: context,
// delegate to customize the search bar
delegate: CustomSearchDelegate());
},
icon: const Icon(Icons.search, color: Colors.black),
)
],
),
backgroundColor: const Color(0xffeeeeee),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 10,
),
Container(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 10),
child: const Text(
'Take a pic!',
style: TextStyle(
fontSize: 35,
fontFamily: 'RobotoBold',
color: Colors.black),
textAlign: TextAlign.left,
),
),
Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
child: const Text('Find out what is wrong with your plant!',
style: TextStyle(
fontSize: 18,
fontFamily: 'RobotoMedium',
color: Color.fromRGBO(102, 124, 138, 1.0)),
textAlign: TextAlign.left),
),
const SizedBox(
height: 10,
),
Container(
color: const Color.fromRGBO(102, 204, 102, 1.0),
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 0),
margin: const EdgeInsets.symmetric(horizontal: 0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Expanded(
child: Text('List of Plants',
style: TextStyle(
fontSize: 30,
fontFamily: 'RobotoBold',
color: Color(0xffeeeeee)),
textAlign: TextAlign.center),
),
],
),
),
GridView.count(
physics: const ScrollPhysics(),
shrinkWrap: true,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
children: <Widget>[
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
ListViewCard(
title: "Bell Pepper",
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const SecondPage(plantname: 'Bell Pepper')));
},
imageOfPlant:
"assets/Images_of_Plant/BellPeper_Image.jpg",
),
],
),
],
),
),
],
),
),
);
}
}
Your gridView's Item give you a specific size but you are setting more than that for your container and text, I suggest you try this:
child: Stack(
children: <Widget>[
//image of the card
Image.asset(
imageOfPlant,
height: double.infinity,
width: 150,
fit: BoxFit.cover,
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: SizedBox(
height: 50,
width: 150,
child: Center(
child: Text(
title,
textAlign: TextAlign.center,
style: const TextStyle(
fontSize: 19,
fontFamily: 'RobotoMedium',
color: Color(0xffeeeeee)), // textstyle
),
),
),
), //text //SizedBox
], // <widget>[]
),
and If you want to change item's AspectRatio you can do this:
GridView.count(
physics: const ScrollPhysics(),
shrinkWrap: true,
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
childAspectRatio: 2 / 3, <--- add this
children: <Widget>[
...
]
)

Flutter - codes not working correctly after putting inside setState

I am trying to add to an array list after user clicked. I am using InkWell, onTap function.
child: InkWell(
onTap: () {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
My debug console is printing these out,
enter image description here
However, when i put the codes inside a setState, this is what got printed
child: InkWell(
onTap: () {
setState(() {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
});
enter image description here
What i am trying to do, is to show/hide the 'trailing' icon in the ListTile, based on whatever user had selected the particular item.
My full codes (without the setState) are as follows,
import 'package:flutter/material.dart';
class Personal1Redo extends StatefulWidget {
#override
_Personal1RedoState createState() => _Personal1RedoState();
}
class _Personal1RedoState extends State<Personal1Redo> {
#override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
List<String> entries = [
'Residental Loan',
'Personal Loan',
'Car Loan',
'Renovation Loan',
'Savings Account',
];
List<String> tempArray = [];
final heading = Column(
children: [
const SizedBox(
height: 40,
),
SizedBox(
height: (mediaQuery.size.height - mediaQuery.padding.top) * 0.1,
child: const Align(
alignment: Alignment.center,
child: Text(
'What do you aspire to do?',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
const SizedBox(
height: 20,
),
],
);
return Scaffold(
appBar: AppBar(
title: Text('Borrower redo'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
heading,
ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (ctx, index) {
return Container(
width: mediaQuery.size.width * 0.9,
padding: const EdgeInsets.all(15),
child: InkWell(
onTap: () {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
},
child: Card(
margin: const EdgeInsets.all(10),
elevation: 8,
child: ListTile(
title: Text(
entries[index],
style: TextStyle(
color: Colors.grey.shade800,
fontSize: 20,
),
textAlign: TextAlign.center,
),
trailing: tempArray.contains(entries[index])
? Icon(Icons.check_box_outline_blank_outlined)
: null,
),
),
),
);
})
],
),
),
);
}
}
Any helps and guidance is very much appreciated, thanks!!
Define variables and functions outside build method.
As setState method, calls build, every time it is called.
Like this :
import 'package:flutter/material.dart';
class Personal1Redo extends StatefulWidget {
#override
_Personal1RedoState createState() => _Personal1RedoState();
}
class _Personal1RedoState extends State<Personal1Redo> {
List<String> entries = [
'Residental Loan',
'Personal Loan',
'Car Loan',
'Renovation Loan',
'Savings Account',
];
List<String> tempArray = [];
getHeadingWidget(BuildContext context) {
return Column(
children: [
const SizedBox(
height: 40,
),
SizedBox(
height: (mediaQuery!.size.height - mediaQuery.padding.top) * 0.1,
child: const Align(
alignment: Alignment.center,
child: Text(
'What do you aspire to do?',
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
const SizedBox(
height: 20,
),
],
);
}
#override
Widget build(BuildContext context) {
final mediaQuery = MediaQuery.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Borrower redo'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
getHeadingWidget(context),
ListView.builder(
shrinkWrap: true,
itemCount: entries.length,
itemBuilder: (ctx, index) {
return Container(
width: mediaQuery.size.width * 0.9,
padding: const EdgeInsets.all(15),
child: InkWell(
onTap: () {
if (tempArray.contains(entries[index].toString())) {
tempArray.remove(entries[index].toString());
print(tempArray.toList().toString());
} else {
tempArray.add(entries[index].toString());
print(tempArray.toList().toString());
}
},
child: Card(
margin: const EdgeInsets.all(10),
elevation: 8,
child: ListTile(
title: Text(
entries[index],
style: TextStyle(
color: Colors.grey.shade800,
fontSize: 20,
),
textAlign: TextAlign.center,
),
trailing: tempArray.contains(entries[index])
? Icon(Icons.check_box_outline_blank_outlined)
: null,
),
),
),
);
})
],
),
),
);
}
}

passing data through the widget constructor

i am missing a small piece of information about constructors, i am trying to pass some data through the widget PromotionCard( [ ... ] ) i can't see any error in my debug console i tried Cards widgets and other different stuff to show the data but i can't find out what is wrong with this code down below.
Note: when i print snapshot.data i can see it perfectly returned
any help please.
**promotions_page.dart**
class PromotionsPage extends StatefulWidget {
#override
_PromotionsPageState createState() => _PromotionsPageState();
}
class _PromotionsPageState extends State<PromotionsPage> {
Future<Result> _promotionsResultsData;
#override
void initState() {
_promotionsResultsData = PromotionApi().fetchPromotions();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
child: ListView(
physics: PageScrollPhysics(),
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Акции',
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'BuffetBold',
),
),
InkWell(
onTap: () => print('Archive promotion pressed!'),
child: Text(
'Архив Акции',
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
fontFamily: 'BuffetBold',
color: Colors.grey[400],
),
),
),
],
),
SizedBox(
height: 10.0,
),
Container(
child: FutureBuilder<Result>(
future: _promotionsResultsData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return GridView.builder(
padding: EdgeInsets.zero,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: (45 / 35),
crossAxisCount: 1,
),
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: snapshot.data.result.length,
itemBuilder: (BuildContext context, int index) {
//print(snapshot.data.result.length);
var promos = snapshot.data.result[index];
PromotionCard(
id: promos.id,
title: promos.title,
description: promos.description,
image: promos.image);
},
);
} else {}
return Center(
child: Text(
"Loading ...",
style: TextStyle(
fontWeight: FontWeight.w900, fontSize: 30.0),
),
);
},
),
),
],
),
],
),
),
);
}
}
i am trying to pass data to this screen
**w_promotion_card.dart**
class PromotionCard extends StatelessWidget {
final String id;
final String title;
final String description;
final String image;
PromotionCard({this.id, this.title, this.description, this.image});
#override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: 200.0,
margin: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 10.0),
padding: EdgeInsets.zero,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(image),
alignment: Alignment.topCenter,
),
borderRadius: BorderRadius.circular(10.0),
border: Border.all(
width: 1.5,
color: Colors.grey[300],
),
),
child: Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.zero,
child: Padding(
padding: EdgeInsets.fromLTRB(10, 170.0, 10.0, 10.0),
child: Text(
title,
style: TextStyle(
fontSize: 16.0,
fontFamily: 'BuffetRegular',
),
),
),
),
);
}
}
You missed the return statement
itemBuilder: (BuildContext context, int index) {
//print(snapshot.data.result.length);
var promos = snapshot.data.result[index];
// you have to return the widget
return PromotionCard(
id: promos.id,
title: promos.title,
description: promos.description,
image: promos.image);
},

How to add item in a listview from one class to another in Flutter?

I am working on a project in which i have a class which has a row that has two children. Child one contains a TabView with a child class TabViewChild in which i am generating a gridview. On the other hand child two contains a listView. So the problem is, when i click on the gridview item i am passing that item's value to a static list and passing that list to a listview of other class. But i have no idea how to change the state of that class on item clicked or how can i achieve this task in a better way as i am new to Flutter. I want that when a person click on any gridview's item that item appears in the listview simultaneously.
class ItemMenus {
int id;
String code;
String name;
String salePrice;
String photo;
String categoryName;
String percentage;
int quantity;
ItemMenus({this.id, this.code, this.name, this.salePrice, this.photo,
this.categoryName, this.percentage, this.quantity});
ItemMenus.fromJson(Map<String, dynamic> json)
:
id = int.parse(json['id']),
code = json['code'],
name = json['name'],
salePrice = json['sale_price'],
photo = json['photo'],
categoryName = json['category_name'],
percentage = json['percentage'];
#override
String toString() {
return 'ItemMenus{id: $id, code: $code, name: $name, salePrice: $salePrice, photo: $photo, categoryName: $categoryName, percentage: $percentage}';
}
}
import 'package:food_app/model/mdl_item_menus.dart';
class ItemMenuList{
List<ItemMenus> _itmMenuLst = [];
ItemMenuList._();
static final ItemMenuList instanceItmMenuLst = ItemMenuList._();
static ItemMenuList get instance => instanceItmMenuLst;
void addItem(ItemMenus im){
_itmMenuLst.add(im);
}
List<ItemMenus> get list => _itmMenuLst;
#override
String toString() {
return 'ItemMenuList{_itmMenuLst: $_itmMenuLst}';
}
}
import 'package:flutter/material.dart';
import 'package:food_app/database/tables/tbl_categories.dart';
import 'package:food_app/model/list/item_menu_list.dart';
import 'package:food_app/model/mdl_categories.dart';
import 'package:food_app/model/mdl_item_menus.dart';
import 'package:food_app/pos/tab_bar_view.dart';
class EPos extends StatefulWidget{
#override
_EPosState createState() => _EPosState();
}
class _EPosState extends State<EPos> {
final categoryDBHelper = TblCategories.categoriesInstance;
final ItemMenuList instance2 = ItemMenuList.instance;
String _orderType = 'Dine-In', _info = 'Table No. 1', _userName = 'ZiaUddin';
List<Categories> catLst = [];
List<ItemMenus> itmLst = [];
Future getCategories() async {
catLst.clear();
var categories = await categoryDBHelper.getCategories();
categories.forEach((element) {
catLst.add(Categories(
id: element['id'],
categoryName: element['category_name'],
description: element['description'],
userId: element['user_id'],
companyId: element['company_id'],
delStatus: element['del_status']));
});
catLst.forEach((element) {
print(element);
});
return catLst;
}
#override
void initState() {
// TODO: implement initState
super.initState();
// itmLst = instance2.list;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Column(
children: [
//#region AppBar
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.15,
color: Colors.redAccent,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
margin: EdgeInsets.fromLTRB(8, 10, 0, 0),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(20),
color: Colors.red,
),
child: Row(
children: [
Icon(
Icons.arrow_back,
color: Colors.white,
size: 25,
),
Padding(
padding: const EdgeInsets.fromLTRB(4, 8, 10, 8),
child: Text(
_orderType,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
fontFamily: 'Ubuntu',
letterSpacing: 2.0,
),
),
),
],
),
),
Container(
margin: EdgeInsets.fromLTRB(8, 10, 0, 0),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(10),
color: Colors.red,
),
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 8),
child: Text(
_info,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.amberAccent,
fontFamily: 'Ubuntu',
letterSpacing: 2.0,
),
),
),
),
Container(
margin: EdgeInsets.only(top: 15, right: 5),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(30),
color: Colors.red,
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 8, 8, 8),
child: Text(
_userName,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
fontFamily: 'Ubuntu',
letterSpacing: 1.0,
),
),
),
CircleAvatar(
backgroundColor: Colors.red,
radius: MediaQuery.of(context).size.height * 0.041,
child: CircleAvatar(
radius: MediaQuery.of(context).size.height * 0.04,
backgroundImage: AssetImage('assets/user.png'),
),
),
],
),
),
],
),
),
//endregion
Expanded(
child: Row(
children: [
//# region Menu
Flexible(
flex: 1,
child: Container(
decoration: BoxDecoration(
color: Colors.yellowAccent,
shape: BoxShape.rectangle,
),
child: Column(
children: [
Expanded(
child: Container(
color: Colors.white,
child: FutureBuilder(
future: getCategories(),
builder: (context, snapShot) {
if (snapShot.connectionState ==
ConnectionState.none &&
snapShot.hasData == null) {
return Center(
child: CircularProgressIndicator());
}
return MaterialApp(
debugShowCheckedModeBanner: false,
home: DefaultTabController(
length: catLst.length,
child: Scaffold(
backgroundColor: Colors.white,
appBar: PreferredSize(
preferredSize:
Size.fromHeight(kToolbarHeight),
child: Container(
height: MediaQuery.of(context)
.size
.height *
0.1,
child: TabBar(
indicatorColor:
Colors.amberAccent,
isScrollable: true,
tabs: catLst
.map<Widget>((Categories c) {
return Tab(
icon: Icon(
Icons.style,
color: Colors.amberAccent,
size: 15,
),
child: Text(
c.categoryName
.toUpperCase(),
style: TextStyle(
color: Colors.black,
fontWeight:
FontWeight.w400,
),
),
);
}).toList(),
),
),
),
body: TabBarView(
children: catLst.map((Categories c) {
return TabBarViewChild(categoryName:c.categoryName,
callback: (){
setState(() {
instance2.addItem(ItemMenus(name: c.categoryName));
itmLst = instance2.list;
print('I am Callback');
});
},);
}).toList(),
),
),
),
);
}),
),
),
],
),
),
),
//endregion
//# region OrderList
Flexible(
flex: 1,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
),
child: ListView.builder(
itemCount: itmLst.length,
itemBuilder: (context, index){
return ListTile(
title: Text(itmLst[index].name),
);
},
),
),
),
//endregion
],
),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:food_app/database/tables/tbl_item_menus.dart';
import 'package:food_app/model/list/item_menu_list.dart';
import 'package:food_app/model/mdl_item_menus.dart';
import 'package:food_app/pos/new_sale.dart';
class TabBarViewChild extends StatefulWidget {
String categoryName;
VoidCallback callback;
TabBarViewChild({Key key,#required this.categoryName, this.callback}) : super(key:key);
#override
_TabBarViewChildState createState() => _TabBarViewChildState();
}
class _TabBarViewChildState extends State<TabBarViewChild> {
final ItemMenuList instance1 = ItemMenuList.instance;
List<ItemMenus> itmLst = [];
final itemMenus = TblItemMenus.itemMenusInstance;
Future getSpecificItemMenus() async{
var items = await itemMenus.getSpecificItemMenus(widget.categoryName);
itmLst.clear();
items.forEach((e) {
itmLst.add(ItemMenus(id: e['id'], categoryName: e['category_name'], code: e['code'],
name: e['name'], percentage: e['percentage'], photo: e['photo'], quantity: e['quantity'],
salePrice: e['sale_price']));
});
for (var value in itmLst) {
print(value);
}
return itmLst;
}
#override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: FutureBuilder(
future: getSpecificItemMenus(),
builder: (context, snapShot) {
if (snapShot.connectionState == ConnectionState.none
&& snapShot.hasData == null) {
return Center(child: CircularProgressIndicator());
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
scrollDirection: Axis.vertical,
itemCount: itmLst.length,
itemBuilder: (context, index){
return Padding(
padding: const EdgeInsets.all(5.0),
child: InkWell(
child: Card(
elevation: 4,
color: Colors.amberAccent,
child: Center(
child: Text(
itmLst[index].name.toUpperCase(),
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.red,
fontSize: 13,
fontWeight: FontWeight.w700,
fontFamily: 'Ubuntu',
letterSpacing: 1.0,
),
),
),
),
onTap: (){
// Provider.of<ProItemMenus>(context, listen: false).addNewItemInList(ItemMenus(name: itmLst[index].name.toUpperCase()));
instance1.addItem(ItemMenus(categoryName: itmLst[index].name.toUpperCase()));
print(itmLst[index].name.toUpperCase());
},
),
);
}
);
}
),
);
}
}
So the problem now, there are two stateful widgets.
And as we are going to share the data or the state between them, basically we need to have more one stateful Widget which will the parent of them.
This term of is this problem known as State Management.
Currently there are many reknown State Management , such as Provider and Bloc. Reference.
But personally, I recommend to use Provider, which has simple Syntaxes and Concept.