Related
I am building a flutter ecommerce app and I am having an issue where ontap isn't working inside my inkwell widget. I want the ontap to work so that I can show the product description. I have placed the inkwell widget as a child inside a Positioned widget, which happens to be one of the children of a Stack. How can I solve this?
Here's my code:
return Card(
shadowColor: Colors.grey,
surfaceTintColor: Colors.amber,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
child: Stack(
children: [
Positioned(
right: 0,
child: InkWell(
onTap: () {
print('tapped');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProductDetails(
id: bottleCategory
.bottleList[index].id,
bottleName: bottleCategory
.bottleList[index]
.bottleName,
image: bottleCategory
.bottleList[index]
.image,
price: bottleCategory
.bottleList[index]
.price)));
},
child: IconButton(
icon: favoriteProvider.isExist(
bottleCategory.bottleList[index])
? Icon(
Icons.favorite,
color: Colors.redAccent,
)
: Icon(
Icons.favorite_border,
),
onPressed: (() {
favoriteProvider.toggleFavorites(
bottleCategory.bottleList[index]);
if (favoriteProvider.isExist(
bottleCategory.bottleList[index])) {
ScaffoldMessenger.of(context)
.hideCurrentSnackBar();
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
content: Text(
"Product Added to Favorite!",
style: TextStyle(fontSize: 16),
),
backgroundColor: Colors.green,
duration: Duration(seconds: 1),
),
);
} else {
ScaffoldMessenger.of(context)
.hideCurrentSnackBar();
ScaffoldMessenger.of(context)
.showSnackBar(
const SnackBar(
content: Text(
"Product Removed from Favorite!",
style: TextStyle(fontSize: 16),
),
backgroundColor: Colors.red,
duration: Duration(seconds: 1),
),
);
}
}),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Image.asset(
bottleCategory.bottleList[index].image,
height: 200.0,
),
),
Center(
child: Text(
bottleCategory
.bottleList[index].bottleName,
style: const TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold))),
Center(
child: Text(
'R${bottleCategory.bottleList[index].price}'),
)
],
),
Positioned(
bottom: 0,
right: 10,
child: IconButton(
icon: const Icon(Icons.add_circle),
iconSize: 40.0,
onPressed: () {
cart.addToCart(
bottleCategory.bottleList[index].id,
bottleCategory
.bottleList[index].bottleName,
bottleCategory
.bottleList[index].price,
bottleCategory
.bottleList[index].image);
},
))
],
),
);
Why do you use IconButton in the child of InkWell?
use one of them and Put all of your onPress functions into that widget.
I have a screen layout like newsfeed instagram
When I come to this screen I got issue like this
problem
I have parent screen where place the bottom bar :
return Scaffold(
body: homeScreenItems[_page],
bottomNavigationBar: Offstage(
offstage: isSwipeLeft,
child: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
label: '',
backgroundColor: primaryColor,
),
BottomNavigationBarItem(
icon: Icon(
Icons.search,
),
label: '',
backgroundColor: primaryColor),
BottomNavigationBarItem(
icon: Icon(
Icons.video_camera_back_outlined,
),
label: '',
),
BottomNavigationBarItem(
icon: Icon(
Icons.favorite,
),
label: '',
backgroundColor: primaryColor,
),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
),
label: '',
backgroundColor: primaryColor,
),
],
onTap: onPageChanged,
currentIndex: _page,
backgroundColor: (_page != 2) ? primaryColor : blackColor,
type: BottomNavigationBarType.fixed,
selectedItemColor: (_page != 2) ? blackColor : primaryColor,
unselectedItemColor: secondaryColor,
),
),
);
This is the place where I code of newsfeed:
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor:
width > webScreenSize ? webBackgroundColor : primaryColor,
appBar: width > webScreenSize
? null
: AppBar(
backgroundColor: primaryColor,
centerTitle: false,
title: SvgPicture.asset(
'assets/ic_instagram.svg',
color: blackColor,
height: 32,
),
actions: [
IconButton(
icon: const Icon(
Icons.add_box_outlined,
color: blackColor,
),
onPressed: () {},
),
IconButton(
icon: const Icon(
Icons.messenger_outline_rounded,
color: blackColor,
),
onPressed: onPress,
),
],
automaticallyImplyLeading: false,
),
body: PageStorage(
bucket: bucketGlobal,
child: ListView.builder(
itemBuilder: (context, index) {
return ItemFeed(
userModel: DataDefault.userModelDemo,
index: index,
);
},
itemCount: DataDefault.userModelDemo.length,
key: PageStorageKey<String>('listFeed'),
shrinkWrap: true,
padding: EdgeInsets.all(5),
scrollDirection: Axis.vertical,
),
),
);
Finally is where I placed feed_Item:
Widget buildFeedItem(List userModel, int index) {
return Column(
children: [
//header
Row(
children: [
CircleAvatar(
backgroundImage: AssetImage(
userModel[index]['userAvaUrl'],
),
),
SizedBox(
width: 5,
),
Text(
userModel[index]['userName'],
),
],
),
SizedBox(
height: 15,
),
//image post
GestureDetector(
onDoubleTap: () {
setState(() {
isLikeAnimating = true;
isHeartAnimating = true;
});
},
child: Stack(
alignment: Alignment.center,
children: [
// list postUrl
SliderImage(
listPost: userModel[index]['postUrl'],
),
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity: isLikeAnimating ? 1 : 0,
child: LikeAnimation(
isAnimating: isLikeAnimating,
child: Icon(
Icons.favorite,
color: isHeartAnimating ? errorColor : primaryColor,
size: 100,
),
duration: const Duration(
milliseconds: 400,
),
onEnd: () {
setState(() {
isLikeAnimating = false;
});
},
),
),
],
),
),
SizedBox(
height: 10,
),
Positioned(
bottom: 0,
left: 0,
right: 0,
child: Container(
// color: blueColor,
child: Row(
children: [
//icon like
CustomIcon(
child: Icon(
isHeartAnimating
? Icons.favorite_rounded
: Icons.favorite_border,
color: isHeartAnimating ? errorColor : blackColor,
size: 30,
),
onPress: () {
setState(() {
isLikeAnimating = true;
isHeartAnimating = !isHeartAnimating;
});
},
isAnimating: isLikeAnimating,
onEnd: () {
setState(
() {
isLikeAnimating = false;
},
);
},
),
SizedBox(
width: 10,
),
//icon comment
CustomIcon(
child: Icon(
Icons.chat_bubble_outline,
color: blackColor,
size: 30,
),
onPress: () {
setState(() {
isCommentAnimating = true;
});
},
isAnimating: isCommentAnimating,
onEnd: () {
setState(
() {
isCommentAnimating = false;
},
);
},
),
SizedBox(
width: 10,
),
//icon share
CustomIcon(
child: Icon(
Icons.send,
color: blackColor,
size: 30,
),
onPress: () {
setState(() {
isShareAnimating = true;
});
},
isAnimating: isShareAnimating,
onEnd: () {
setState(
() {
isShareAnimating = false;
},
);
},
),
//icon save
Expanded(
child: Align(
alignment: Alignment.bottomRight,
child: CustomIcon(
child: Icon(
isSave
? Icons.bookmark_added_rounded
: Icons.bookmark_border,
color: isSave ? saveColor : blackColor,
size: 30,
),
onPress: () {
setState(() {
isSaveAnimating = true;
isSave = !isSave;
});
},
isAnimating: isSaveAnimating,
onEnd: () {
setState(
() {
isSaveAnimating = false;
},
);
},
),
),
),
],
),
),
),
],
);
}
#override
Widget build(BuildContext context) {
return Container(
key: PageStorageKey<String>('listFeed'),
child: buildFeedItem(
widget.userModel,
widget.index,
),
);
}
Where did I do wrong? Please help me
Positioned need a StackParentData as it's parent.
But Column is not.
Put Positioned in Stack may resolve your problem.
Here in the below image I have added showModalBottomSheet on clicking on the item of "Bottom Navigation Bar", but the BottomNavigationBar is hidden by the modal sheet, So I want to make it visible even the bottom sheet is present. Can anyone please anyone help me out.
This is my bottom navigation code:
Widget _bottomNavigationBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
key: scaffoldState,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.branding_watermark_outlined),
label: 'Brands',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: 'Category',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
)
],
currentIndex: _selectedIndex,
selectedItemColor: AppColors.blue,
onTap: (newIndex) => {
if (newIndex == 1)
{showBrandsBottomSheet(context)}
else if (newIndex == 2)
{showCategoryBottomSheet(context)}
else
{
setState(() {
_selectedIndex = newIndex;
})
}
});
}
Here is my code for bottom model sheet:
showBrandsBottomSheet(BuildContext context) {
return showModalBottomSheet<void>(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15.0), topRight: Radius.circular(15.0)),
),
context: context,
useRootNavigator: true,
isScrollControlled: true,
builder: (BuildContext _) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).size.height / 2,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 5, top: 3),
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: const Align(
alignment: Alignment.topRight,
child: Icon(Icons.close)),
),
),
Container(
color: Colors.white,
height: 350,
child: ListView.builder(
key: Key('builder ${_selected.toString()}'), //a
scrollDirection: Axis.vertical,
// shrinkWrap: true,
// physics: NeverScrollableScrollPhysics(),
itemCount: brandList.length,
itemBuilder: (BuildContext context, int index) {
return Theme(
data: Theme.of(context)
.copyWith(dividerColor: Colors.white),
child: ExpansionTile(
// tilePadding: const EdgeInsets.all(0),
key: Key(index.toString()), //attention
initiallyExpanded: index == _selected, //attention
collapsedIconColor: Colors.blue,
iconColor: Colors.blue,
backgroundColor: Colors.white,
title: Text(
brandList[index],
style: const TextStyle(
fontSize: 13.0,
color: Colors.black,
fontWeight: FontWeight.w600),
),
children: <Widget>[
Container(
color: Colors.blue[50],
child: Column(
children: _buildExpandableBrands(brandList),
),
),
],
onExpansionChanged: ((newState) {
if (newState) {
setState(() {
const Duration(seconds: 20000);
_selected = index;
});
} else {
setState(() {
_selected = -1;
});
}
}),
));
},
),
),
],
),
),
);
},
);
}
set useRootNavigator=true.This will display model sheet above all other content.
showModalBottomSheet(
context: context,
isScrollControlled: true,
useRootNavigator: true,
builder: (context) {
return BottomBarView(
);
});
Finally, this question helped me in getting this done.
Here is my working code:
Widget _bottomNavigationBar() {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
key: scaffoldState,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.branding_watermark_outlined),
label: 'Brands',
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: 'Category',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile',
)
],
currentIndex: _selectedIndex,
selectedItemColor: AppColors.blue,
onTap: (newIndex) => {
if (newIndex == 1)
{
_scaffoldKey.currentState?.showBottomSheet((_) => Container(
child: showBrandsBottomSheet(),
))
}
else if (newIndex == 2)
{
{
_scaffoldKey.currentState?.showBottomSheet((_) => Container(
child: showCategoryBottomSheet(),
))
}
}
else
{
setState(() {
_selectedIndex = newIndex;
})
}
});
}
showBrandsBottomSheet:
showBrandsBottomSheet() {
return Container(
color: Colors.white,
height: MediaQuery.of(context).size.height / 2,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 5, top: 3),
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: const Align(
alignment: Alignment.topRight, child: Icon(Icons.close)),
),
),
Container(
color: Colors.white,
height: 350,
child: ListView.builder(
key: UniqueKey(),
scrollDirection: Axis.vertical,
itemCount: brandList.length,
itemBuilder: (BuildContext context, int index) {
cardKeyList.add(GlobalKey(debugLabel: "index :$index"));
return Theme(
data: Theme.of(context)
.copyWith(dividerColor: Colors.white),
child: ExpansionTileCard(
key: cardKeyList[index],
initiallyExpanded: false,
title: Text(
brandList[index],
style: const TextStyle(
fontSize: 13.0,
color: Colors.black,
fontWeight: FontWeight.w600),
),
children: <Widget>[
Container(
color: Colors.blue[50],
child: Column(
children: _buildExpandableBrands(brandList),
),
),
],
onExpansionChanged: (value) {
if (value) {
Future.delayed(const Duration(milliseconds: 200),
() {
for (var i = 0; i < cardKeyList.length; i++) {
if (index != i) {
cardKeyList[i].currentState?.collapse();
}
}
});
}
},
));
},
),
),
],
),
),
);
}
Now it is started showing above the bottom navigation.
I am making a app in which I am using package snake bottom navigation and advanced drawer. Both are configured fine in a file but I'm having issue when when I want to use the function on a new page to open and close the drawer. I am unable to import it to my HomePage file where I am making the home page of the app. This code
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
is the one creating issue in the drawer screen onpressed and on valuelistener.
Here is my Dashboard code which contains bottom nav and drawer:
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
#override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
final _advancedDrawerController = AdvancedDrawerController();
int _selectedIndex = 0;
final PageController _pageController = PageController();
ShapeBorder? bottomBarShape = const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(25)),
);
SnakeBarBehaviour snakeBarStyle = SnakeBarBehaviour.floating;
EdgeInsets padding = const EdgeInsets.all(12);
SnakeShape snakeShape = SnakeShape.circle;
bool showSelectedLabels = true;
bool showUnselectedLabels = true;
Color selectedColor = Colors.black;
Gradient selectedGradient =
const LinearGradient(colors: [Colors.red, Colors.amber]);
Color unselectedColor = Colors.black;
Gradient unselectedGradient =
const LinearGradient(colors: [Colors.black, Colors.black]);
Color? containerColor;
List<Color> containerColors = [
const Color(0xFFFDE1D7),
const Color(0xFFE4EDF5),
const Color(0xFFE7EEED),
const Color(0xFFF4E4CE),
];
#override
Widget build(BuildContext context) {
return AdvancedDrawer(
backdropColor: kblue,
controller: _advancedDrawerController,
animationCurve: Curves.easeInOut,
animationDuration: const Duration(milliseconds: 300),
animateChildDecoration: true,
rtlOpening: false,
disabledGestures: false,
childDecoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
drawer: SafeArea(
child: Container(
color: kblue,
child: ListTileTheme(
textColor: Colors.white,
iconColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 128.0,
height: 128.0,
margin: const EdgeInsets.only(
top: 24.0,
bottom: 64.0,
),
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Image.asset(
'assets/logo.png',
scale: 3,
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.home),
title: const Text(
'Home',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.account_circle_rounded),
title: const Text(
'Profile',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.notifications),
title: const Text(
'Notifications',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.bug_report),
title: const Text(
'Report a bug',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.logout),
title: const Text(
'Logout',
style: TextStyle(),
),
),
const Spacer(),
DefaultTextStyle(
style: const TextStyle(
fontSize: 12,
),
child: GestureDetector(
onTap: () {},
child: Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0,
),
child: const Text(
'Terms of Service | Privacy Policy',
style: TextStyle(),
),
),
),
),
],
),
),
),
),
child: Scaffold(
extendBodyBehindAppBar: true,
resizeToAvoidBottomInset: true,
extendBody: true,
bottomNavigationBar: SnakeNavigationBar.color(
behaviour: snakeBarStyle,
snakeShape: snakeShape,
shape: bottomBarShape,
padding: padding,
snakeViewColor: selectedColor,
selectedItemColor: snakeShape == SnakeShape.indicator
? selectedColor
: Colors.orange,
unselectedItemColor: Colors.black,
showUnselectedLabels: showUnselectedLabels,
showSelectedLabels: showSelectedLabels,
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'tickets'),
BottomNavigationBarItem(
icon: Icon(Icons.person), label: 'calendar'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'home'),
BottomNavigationBarItem(
icon: Icon(Icons.person), label: 'microphone'),
BottomNavigationBarItem(icon: Icon(Icons.person), label: 'search'),
],
selectedLabelStyle: const TextStyle(fontSize: 14),
unselectedLabelStyle: const TextStyle(fontSize: 10),
),
body: PageView(
controller: _pageController,
children: const <Widget>[
HomePage(),
HomePage(),
HomePage(),
HomePage(),
HomePage(),
],
onPageChanged: (page) {
setState(() {
_selectedIndex = page;
});
},
),
),
);
}
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
}
Code to HomePage which contains the button to open and close the drawer and thats where the issue is:
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: SafeArea(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
onPressed: _handleMenuButtonPressed,
icon: ValueListenableBuilder<AdvancedDrawerValue>(
valueListenable: _advancedDrawerController,
builder: (_, value, __) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
child: Icon(
value.visible ? Icons.clear : Icons.menu,
key: ValueKey<bool>(value.visible),
),
);
},
),
),
],
),
),
],
),
),
),
);
}
}
You can do it this way. There's no need to separate the files when you can do in one
class Dashboard extends StatefulWidget {
const Dashboard({Key? key}) : super(key: key);
#override
State<Dashboard> createState() => _DashboardState();
}
class _DashboardState extends State<Dashboard> {
final _advancedDrawerController = AdvancedDrawerController();
int _selectedIndex = 0;
final PageController _pageController = PageController();
ShapeBorder? bottomBarShape = const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
);
SnakeBarBehaviour snakeBarStyle = SnakeBarBehaviour.floating;
EdgeInsets padding = const EdgeInsets.only(top: 0);
SnakeShape snakeShape = SnakeShape.circle;
final double elevation = 4;
bool showSelectedLabels = true;
bool showUnselectedLabels = true;
Color selectedColor = Colors.white;
Gradient selectedGradient =
const LinearGradient(colors: [Colors.blue, Colors.pink]);
Color unselectedColor = Colors.black;
Gradient unselectedGradient =
const LinearGradient(colors: [Colors.black, Colors.black]);
Color? containerColor;
List<Color> containerColors = [
const Color(0xFFFDE1D7),
const Color(0xFFE4EDF5),
const Color(0xFFE7EEED),
const Color(0xFFF4E4CE),
];
#override
Widget build(BuildContext context) {
return AdvancedDrawer(
backdropColor: kblue,
controller: _advancedDrawerController,
animationCurve: Curves.easeInOut,
animationDuration: const Duration(milliseconds: 300),
animateChildDecoration: true,
rtlOpening: false,
disabledGestures: false,
childDecoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
drawer: SafeArea(
child: Container(
color: kblue,
child: ListTileTheme(
textColor: Colors.white,
iconColor: Colors.white,
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Container(
width: 128.0,
height: 128.0,
margin: const EdgeInsets.only(
top: 24.0,
bottom: 64.0,
),
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
),
child: Image.asset(
'assets/logo.png',
scale: 3,
),
),
ListTile(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const Dashboard()));
},
leading: const Icon(Icons.home),
title: const Text(
'Home',
style: TextStyle(),
),
),
ListTile(
onTap: () {},
leading: const Icon(Icons.account_circle_rounded),
title: const Text(
'Profile',
style: TextStyle(),
),
),
ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const NotificationsScreen()));
},
leading: const Icon(Icons.notifications),
title: const Text(
'Notifications',
style: TextStyle(),
),
),
ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => ReportBug()));
},
leading: const Icon(Icons.bug_report),
title: const Text(
'Report a bug',
style: TextStyle(),
),
),
ListTile(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const LoginPage()));
},
leading: const Icon(Icons.logout),
title: const Text(
'Logout',
style: TextStyle(),
),
),
const Spacer(),
DefaultTextStyle(
style: const TextStyle(
fontSize: 12,
),
child: GestureDetector(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => const TermsandPolicies()));
},
child: Container(
margin: const EdgeInsets.symmetric(
vertical: 16.0,
),
child: const Text(
'Terms of Service | Privacy Policy',
style: TextStyle(),
),
),
),
),
],
),
),
),
),
child: Scaffold(
appBar: AppBar(
backgroundColor: const Color(0xFFFAFAFA),
elevation: 0,
centerTitle: true,
title: const Text(
'Dhrop',
style: TextStyle(
letterSpacing: 1,
color: Colors.black,
),
),
automaticallyImplyLeading: false,
leading: IconButton(
onPressed: _handleMenuButtonPressed,
icon: ValueListenableBuilder<AdvancedDrawerValue>(
valueListenable: _advancedDrawerController,
builder: (_, value, __) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
child: Icon(
value.visible ? Icons.clear : Icons.menu,
color: Colors.black,
key: ValueKey<bool>(value.visible),
),
);
},
),
),
),
extendBodyBehindAppBar: true,
resizeToAvoidBottomInset: true,
extendBody: true,
bottomNavigationBar: SnakeNavigationBar.color(
backgroundColor: kblue,
behaviour: snakeBarStyle,
snakeShape: snakeShape,
shape: bottomBarShape,
padding: const EdgeInsets.only(
bottom: 15,
left: 10,
right: 10,
),
snakeViewColor: selectedColor,
selectedItemColor:
snakeShape == SnakeShape.indicator ? selectedColor : kblue,
unselectedItemColor: Colors.black,
showUnselectedLabels: showUnselectedLabels,
showSelectedLabels: showSelectedLabels,
currentIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
items: [
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.home,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const HomePage()));
},
),
// label: 'Home',
),
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.search,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SearchPage()));
},
),
// label: 'Search',
),
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.message,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const MessagesPage()));
},
),
// label: 'Messages',
),
BottomNavigationBarItem(
icon: IconButton(
icon: const Icon(
Icons.luggage,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DropPage()));
},
),
// label: 'Drop',
),
],
selectedLabelStyle: const TextStyle(fontSize: 12),
unselectedLabelStyle: const TextStyle(fontSize: 14),
),
body: PageView(
controller: _pageController,
children: const <Widget>[
HomePage(),
SearchPage(),
MessagesPage(),
DropPage()
],
onPageChanged: (page) {
setState(() {
_selectedIndex = page;
});
},
),
),
);
}
void _handleMenuButtonPressed() {
_advancedDrawerController.showDrawer();
}
}
i'm a bit new to flutter and i'm trying to teach myself to build a groceries list, which will be linked to an API backend. I want the text on a listtile to be editable ontap, so if the user makes a typo they can quickly edit the listtile without going through an additional dialogue.
Screenshot of list tiles
Code:
Widget _shoppingListItem() {
return ListView.builder(
itemCount:
_shoppingList.shoppingListCategories.first.shoppingListItems.length,
itemBuilder: (context, index) {
return Dismissible(
background: Container(
child: Text("Delete",
style: TextStyle(
fontWeight: FontWeight.normal, color: Colors.white)),
color: Colors.red,
),
confirmDismiss: (direction) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Sure??'),
content: Text('Delete'),
actions: <Widget>[
FlatButton(
onPressed: () {
// Navigator.pop(context, false);
Navigator.of(
context,
// rootNavigator: true,
).pop(false);
},
child: Text('No'),
),
FlatButton(
onPressed: () {
// Navigator.pop(context, true);
Navigator.of(
context,
// rootNavigator: true,
).pop(true);
},
child: Text('Yes'),
),
],
);
},
);
},
key: UniqueKey(),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 1,
blurRadius: 6,
offset: Offset(0, 3), // changes position of shadow
),
],
),
child: ListTile(
title: Text(
_shoppingList.shoppingListCategories.first
.shoppingListItems[index].itemName,
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
color: ColorPalette.dark2,
icon: icons.shoppingMinus.image(size: 24),
onPressed: () {
setState(() {
_shoppingList.shoppingListCategories.first
.shoppingListItems[index].itemCount--;
});
},
),
Text(
"${_shoppingList.shoppingListCategories.first.shoppingListItems[index].itemCount}",
style: TextStyle(
color: ColorPalette.dark2,
),
),
IconButton(
color: ColorPalette.dark2,
icon: icons.shoppingPlus.image(size: 24),
onPressed: () {
setState(() {
_shoppingList.shoppingListCategories.first
.shoppingListItems[index].itemCount++;
});
},
),
],
),
),
),
),
);
},
);
}
}