Container has its size restrained when using with BottomNavigationBar - android

I have a screen that is applied with BottomNavigationBar. With the index = 0, it will lead to home.dart.
Inside home.dart, I want to have to a column of Widgets. It contains 2 titles(put in Row widgets) and 2 listViews. The 1st ListView I want it to scroll horizontally, and the 2nd one vertical. Both ListView is scrollable. However, it seems that both lists(or containers) are restrained in size somehow, because the 2nd ListView scroll behavior is that it only scroll inside the bottom half of the screen, not the whole screen.
I thought of adding a SingleChildScrollView with Expanded outside the whole Container in home.dart. But it return the error
mainScreen.dart
int _currentTab = 0;
void onTabTapped(int tabNumber) {
setState(() {
_currentTab = tabNumber;
});
}
#override
void initState() {
super.initState();
this.setState(() {
contents = [
HomeTab(),
DownloadedTab(),
SettingTab()
];
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Container(
child: contents != null ? contents[_currentTab] : Text("Page is loaded"),
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: onTabTapped,
backgroundColor: Theme.ColorsMode.appBarGradientStart,
currentIndex: _currentTab,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text('Home')),
BottomNavigationBarItem(
icon: new Icon(Icons.file_download),
title: new Text('Download')),
BottomNavigationBarItem(
icon: new Icon(Icons.settings),
title: new Text('Setting')),
],
),
),
);
}
home.dart
#override
Widget build(Build context) {
return Container(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Course', textAlign: TextAlign.left, style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
Expanded(
child: Container(
// height: 6000.0,
child: ListView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: (showInHomeClass != null && showInHomeClass != null) ? showInHomeClass.length : 0,
itemBuilder: (context, index) {
return Container(
width: MediaQuery.of(context).size.width * 0.6,
child: FittedBox(
fit: BoxFit.cover,
child: GestureDetector(
onTap: () {},
child: Card(
child: Center (
child: Image.network('https://example.com'),
),
),
),
),
);
}
),
),
),
Row(
children: <Widget>[
Text('News', textAlign: TextAlign.left, style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)),
],
),
Expanded(
child: Container(
// height: 6000.0,
child: ListView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
itemCount: (showInHomeClass != null && showInHomeClass != null) ? showInHomeClass.length : 0,
itemBuilder: (context, index) {
return Container(
width: MediaQuery.of(context).size.width * 0.6,
child: FittedBox(
fit: BoxFit.cover,
child: GestureDetector(
onTap: () {},
child: Card(
child: Center (
child: Image.network('https://example.com'),
),
),
),
),
);
}
),
),
)
],
),
);
}
error when adding SingleChildScrollView and Expanded
════════ Exception caught by widgets library ═══════════════════════════════════
The following assertion was thrown building Listener:
'package:flutter/src/widgets/framework.dart': Failed assertion: line 1786 pos 12: '_elements.contains(element)': is not true.
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=BUG.md
The relevant error-causing widget was
SingleChildScrollView
lib\…\Home\Home.dart:115
#4 Element.inflateWidget
package:flutter/…/widgets/framework.dart:3176
#5 Element.updateChild
package:flutter/…/widgets/framework.dart:2988
#6 SingleChildRenderObjectElement.mount
package:flutter/…/widgets/framework.dart:5445
...
════════════════════════════════════════════════════════════════════════════════
Reloaded 6 of 675 libraries in 919ms.
════════ Exception caught by widgets library ═══════════════════════════════════
'package:flutter/src/widgets/framework.dart': Failed assertion: line 1786 pos 12: '_elements.contains(element)': is not true.
The relevant error-causing widget was
SingleChildScrollView
Any suggestions?

Related

Link with a image and gestureDetector

I am making a app for fun and to learn. When I added interactivity by first time, I found a error by adding gesturedetector. Gesture detector has to open a new function which is a window with more things. The gesture detector is inside a column, inside a container inside a ListView (The order is LsitView->Container->GestureDetector)
class _HomePageUserState extends State<HomePageUser> {
#override
Widget build(BuildContext context) {
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
//itemCount: 100,
itemBuilder: (context, index) {
return Center(
child: Container (
height: 300,
width: 400,
alignment:Alignment.center,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(10.0),
),
child: Stack(
children: <Widget> [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(padding: EdgeInsets.all(10), child: Text('Nombre del comercio'),),
Padding(padding: EdgeInsets.only(left: 10), child: Icon(Icons.open_in_new),),
],
),
Expanded(
child: GestureDetector(
child: Image.network('https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg/800px-Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg',
fit: BoxFit.fitWidth,
height: 200,),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const VistaUsuario()),
);
},
onLongPress: () {},
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(padding: EdgeInsets.all(10), child: Text('Estrellas'),),
Padding(padding: EdgeInsets.all(10), child: Text('Precio (rango)'),),
],
),
],
),
],
),
),
);
},
);
}
}
The error is:
Se produjo una excepción. FlutterError (Vertical viewport was given unbounded height. Viewports expand in the scrolling direction to fill their container. In this case, a vertical viewport was given an unlimited amount of vertical space in which to expand. This situation typically happens when a scrollable widget is nested inside another scrollable widget. If this widget is always nested in a scrollable widget there is no need to use a viewport because there will always be enough vertical space for the children. In this case, consider using a Column instead. Otherwise, consider using the "shrinkWrap" property (or a ShrinkWrappingViewport) to size the height of the viewport to the sum of the heights of its children.)
Try to wrap your GestureDetector in SingleChildScrollView .this will scroll the page.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test page'),
),
body:SingleChildScrollView(
child:Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
child: Image.network('https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg/800px-Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg',
fit: BoxFit.fitWidth,
height: 200,),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const VistaUsuario()),
);
},
),
],
),
),
),
);
}
Another Solution is to use Expanded widget.This will expand the image to take rest of the page
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test page'),
),
body:Center(
child:Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 0,
),
Expanded(
child: GestureDetector(
child: Image.network('https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg/800px-Spaghetti_Bolognese_mit_Parmesan_oder_Grana_Padano.jpg',
fit: BoxFit.fitWidth,
height: 200,),
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => const VistaUsuario()),
);
},
),
),
],
),
),
),
);
}

How to fix overflow in flutter

here is my app
as you can see working well, I installed this on my phone, and it works fine too.
and I send this to my friend, and his phone showing like this
mine and his phone is same phone, literally same phone, but in his and any others phone is showing this overflow, mine and this emulator have no problem, how do i fix overflow problem
class Homescreen extends StatelessWidget {
const Homescreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text("Pluto Guess Game"),
backgroundColor: Colors.white60,
),
body: Container(
color: Colors.white,
child: SafeArea(
child: ListView(
children: [
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PlayerWidget(
player: messi
),
PlayerWidget(
player: neymar
)
],
),
),
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PlayerWidget(
player: mbappe
)
PlayerWidget(
player: ramos
)
],
),
),
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PlayerWidget(
player: messi
),
PlayerWidget(
player: neymar
)
],
),
),
Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PlayerWidget(
player: messi
),
PlayerWidget(
player: neymar
)
],
),
),
Card(
child: IconButton(
icon: const Icon(Icons.gesture),
iconSize: 50,
color: Colors.black,
splashColor: Colors.orange,
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (nav) {
return const Asking();
},
),
);
},
),
),
],
),
),
),
),
);
}
}
and also I'm new at flutter, I know I'm doing lot of mistake in this code please suggest that also
->Use This Code
Widget build(BuildContext context) {
double h = MediaQuery.of(context).size.height;
double w = MediaQuery.of(context).size.width;
return Scaffold(
appBar: getAppBar(context, "Back", "", []),
body: SafeArea(
top: true,
bottom: true,
child: Column(
children: [
Expanded(
child: ListView.builder(
shrinkWrap: true,
physics: BouncingScrollPhysics(),
itemCount: 15,
itemBuilder: (context,v){
return
Container(
padding: EdgeInsets.only(left: 15.0,right: 15.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
height: h*0.2,
width: w*0.4,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(25.0)
),
),
Container(
height: h*0.2,
width: w*0.4,
decoration: BoxDecoration(
color: Colors.black38,
borderRadius: BorderRadius.circular(25.0)
),
),
],
),
SizedBox(height: 15.0,),
Divider(
color: Colors.black,
),
SizedBox(height: 15.0,),
],
),
);
}),
)
],
),
),
);
}
Without your code I can't make corrections to the current code. but if you need responsive UI that work regardless of screen size, I suggest you use Rows, Columns with Expanded Widget, as necessary.
for example if you need to have 2 Items inside a Row where each occupies same space you can use,
Row (
children: [
Expanded (
flex:1
child: YourWidget()
),
Expanded (
flex:1
child: YourWidget()
)
]
)
Remember to remove hardcoded size properties along the main axis of your Colum or Row.
Same goes for Columns.
If you need each to have varied sizes, you can use flex property of the Expanded Widget. for example, one items has 1/3 of width and other has 2/3 you can put 1 and 2 as flex values.
more explanation from flutter team: Expanded

I am trying to wrap my Column widget in a SingleChildScrollView but not able to

I am trying to wrap my column widget in a single child scroll view since I am getting overflow. But when I am trying to wrap it, I am receiving errors such as
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
RenderBox was not laid out: RenderFlex#dc736 relayoutBoundary=up12 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1930 pos 12: 'hasSize'
What can I do to prevent overflow of pixels in my app ? Here is my code:
return Scaffold(
appBar: AppBar(
title: Text('Edit your pet`s details'),
backgroundColor: Color.fromRGBO(101, 69, 112, 1.0),
),
body: Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget> [
Row(
children: <Widget>[
Expanded(
child: TextFieldWidget(
controller: _petNameController,
helperText: "Pet's Name",
)),
],
),
Padding(
padding: const EdgeInsets.only(left: 50.0, right: 50.0),
child: Divider(
color: Colors.grey,
thickness: 0.5,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: 60.0,),
Text(
"$_petName is a $_petGender. Update gender",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w400,
),
)
],
),
Expanded(
child: GridView.count(
crossAxisCount: 2,
primary: false,
scrollDirection: Axis.vertical,
children: List.generate(petGenders.length, (index) {
return GestureDetector(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)),
color:
selectedIndex == index ? primaryColor : null,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
petGenders[petKeys[index]],
SizedBox(
height: 15.0,
),
Text(
petKeys[index],
style: TextStyle(
color: selectedIndex == index
? Colors.white
: null,
fontSize: 18.0,
fontWeight: FontWeight.w600),
),
],
),
),
),
onTap: () {
setState(() {
widget.pet.gender = petKeys[index];
selectedIndex = index;
});
});
}),
),
),
The error comes from the fact that your Column contains an Extended widget, which forces to use the maximum vertical space.
The SingleScrollChildView has no limit to vertical space it can use.
The result is that you have a widget that try to take an infinite vertical space.
How can you fix that ?
Either, remove the Extended widget, or the SingleScrollChildView widget.
Or, you can also wrap your Extended widget with another widget with a defined size or constraints like a Container with the properties height and width.

current way to use List in flutter for scrollable with expanded or flex

my screen is not scrollable , and has limit height ( only scrollable in the limit height )
I do want to make my page on there for scrollable,
here is my current page now :
if you see in the gif above, my page is not scrollable and only stuck in the one box and scrollable inside, I do love to scroll able them for all page normally, should I use ListView here ?? but how can I make the pic and text for responsive like above ? but I do make the hight of text too close also, can I know how u tiny up the text on the list also ??
here is my code for that Widget
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
data['title'],
softWrap: true,
),
),
body: Container(
padding: EdgeInsets.all(MediaQuery.of(context).size.width * 0.05),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
flex: 1,
child: Align(
alignment: Alignment.center,
child: Image.network('https://i.ibb.co/nrWqyMx/belgium.png'),
)
),
Expanded(
flex: 2,
child: Align(
alignment: Alignment.topLeft,
child: ListView.builder(
itemBuilder: (ctx, index) {
return Container(
height: MediaQuery.of(context).size.width * 0.14,
child: ListTile(
leading: Icon(Icons.radio_button_checked, size: 17),
title: Text(data['ingredients'][index], style: TextStyle(height: 1.3),),
)
);
},
itemCount: data['ingredients'].length,
),
)
)
],
),
),
);
}
link : flutter codepen
Scaffold(
appBar: AppBar(
title: Text(
'MyAppBar',
style:
TextStyle(color: Colors.cyan[100], fontWeight: FontWeight.bold),
),
),
body: ListView(
children: <Widget>[
Container(
child: Image.network
('https://i.ibb.co/nrWqyMx/belgium.png'),
),
ListView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, index) {
return Container(
height: MediaQuery.of(context).size.width * 0.14,
child: ListTile(
leading: Icon(Icons.radio_button_checked, size: 17),
title: Text("data['ingredients'][index]", style: TextStyle(height: 1.3),),
)
);
},
itemCount:25,
)
],
),
);
You will need put a ScrollView as a main container of your widget. Something like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
color: Colors.red,
child: SingleChildScrollView(
child: Column(
children: [
Text("Title"),
ListView.builder(
shrinkWrap: true,
itemCount: 3,
itemBuilder: (context, index) {
return Container(
height: 300,
width: double.infinity,
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(
color: Colors.black,
style: BorderStyle.solid
)
),
);
},
)
],
),
),
)
);
}
}

Swipe List Item for more options (Flutter)

Somedays ago I decided to choose an Ui for an app from Pinterest to practice building apps with Flutter but I'm stuck with the Slider which shows an "more" and "delete" button on horizontal drag. Picture on the right.
I don't have enough knowledge to use Gestures combined with Animations to create something like this in flutter. Thats why I hope that someone of you can make an example for everyone like me that we can understand how to implement something like this in a ListView.builder.
(Source)
An gif example from the macOS mail App:
I created a package for doing this kind of layout: flutter_slidable (Thanks Rémi Rousselet for the based idea)
With this package it's easier to create contextual actions for a list item. For example if you want to create the kind of animation you described:
You will use this code:
new Slidable(
delegate: new SlidableDrawerDelegate(),
actionExtentRatio: 0.25,
child: new Container(
color: Colors.white,
child: new ListTile(
leading: new CircleAvatar(
backgroundColor: Colors.indigoAccent,
child: new Text('$3'),
foregroundColor: Colors.white,
),
title: new Text('Tile n°$3'),
subtitle: new Text('SlidableDrawerDelegate'),
),
),
actions: <Widget>[
new IconSlideAction(
caption: 'Archive',
color: Colors.blue,
icon: Icons.archive,
onTap: () => _showSnackBar('Archive'),
),
new IconSlideAction(
caption: 'Share',
color: Colors.indigo,
icon: Icons.share,
onTap: () => _showSnackBar('Share'),
),
],
secondaryActions: <Widget>[
new IconSlideAction(
caption: 'More',
color: Colors.black45,
icon: Icons.more_horiz,
onTap: () => _showSnackBar('More'),
),
new IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () => _showSnackBar('Delete'),
),
],
);
There's already a widget for this kind of gesture. It's called Dismissible.
You can find it here. https://docs.flutter.io/flutter/widgets/Dismissible-class.html
EDIT
If you need the exact same transtion, you'd probably have to implement if yourself.
I made a basic example. You'd probably want to tweak the animation a bit, but it's working at least.
class Test extends StatefulWidget {
#override
_TestState createState() => new _TestState();
}
class _TestState extends State<Test> {
double rating = 3.5;
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new ListView(
children: ListTile
.divideTiles(
context: context,
tiles: new List.generate(42, (index) {
return new SlideMenu(
child: new ListTile(
title: new Container(child: new Text("Drag me")),
),
menuItems: <Widget>[
new Container(
child: new IconButton(
icon: new Icon(Icons.delete),
),
),
new Container(
child: new IconButton(
icon: new Icon(Icons.info),
),
),
],
);
}),
)
.toList(),
),
);
}
}
class SlideMenu extends StatefulWidget {
final Widget child;
final List<Widget> menuItems;
SlideMenu({this.child, this.menuItems});
#override
_SlideMenuState createState() => new _SlideMenuState();
}
class _SlideMenuState extends State<SlideMenu> with SingleTickerProviderStateMixin {
AnimationController _controller;
#override
initState() {
super.initState();
_controller = new AnimationController(vsync: this, duration: const Duration(milliseconds: 200));
}
#override
dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final animation = new Tween(
begin: const Offset(0.0, 0.0),
end: const Offset(-0.2, 0.0)
).animate(new CurveTween(curve: Curves.decelerate).animate(_controller));
return new GestureDetector(
onHorizontalDragUpdate: (data) {
// we can access context.size here
setState(() {
_controller.value -= data.primaryDelta / context.size.width;
});
},
onHorizontalDragEnd: (data) {
if (data.primaryVelocity > 2500)
_controller.animateTo(.0); //close menu on fast swipe in the right direction
else if (_controller.value >= .5 || data.primaryVelocity < -2500) // fully open if dragged a lot to left or on fast swipe to left
_controller.animateTo(1.0);
else // close if none of above
_controller.animateTo(.0);
},
child: new Stack(
children: <Widget>[
new SlideTransition(position: animation, child: widget.child),
new Positioned.fill(
child: new LayoutBuilder(
builder: (context, constraint) {
return new AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return new Stack(
children: <Widget>[
new Positioned(
right: .0,
top: .0,
bottom: .0,
width: constraint.maxWidth * animation.value.dx * -1,
child: new Container(
color: Colors.black26,
child: new Row(
children: widget.menuItems.map((child) {
return new Expanded(
child: child,
);
}).toList(),
),
),
),
],
);
},
);
},
),
)
],
),
);
}
}
EDIT
Flutter no longer allows type Animation<FractionalOffset> in SlideTransition animation property. According to this post https://groups.google.com/forum/#!topic/flutter-dev/fmr-C9xK5t4 it should be replaced with AlignmentTween but this also doesn't work. Instead, according to this issue: https://github.com/flutter/flutter/issues/13812 replacing it instead with a raw Tween and directly creating Offset object works instead. Unfortunately, the code is much less clear.
Updated Code with Null Safety: Flutter: 2.x
Firstly you need to add the flutter_slidable package in your project and add below code then Let's enjoy...
Slidable(
actionPane: SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
child: Container(
color: Colors.white,
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.indigoAccent,
child: Text('$3'),
foregroundColor: Colors.white,
),
title: Text('Tile n°$3'),
subtitle: Text('SlidableDrawerDelegate'),
),
),
actions: <Widget>[
IconSlideAction(
caption: 'Archive',
color: Colors.blue,
icon: Icons.archive,
onTap: () => _showSnackBar('Archive'),
),
IconSlideAction(
caption: 'Share',
color: Colors.indigo,
icon: Icons.share,
onTap: () => _showSnackBar('Share'),
),
],
secondaryActions: <Widget>[
IconSlideAction(
caption: 'More',
color: Colors.black45,
icon: Icons.more_horiz,
onTap: () => _showSnackBar('More'),
),
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () => _showSnackBar('Delete'),
),
],
);
I have a task that needs the same swipeable menu actions I tried answeres of Romain Rastel and Rémi Rousselet. but I have complex widget tree. the issue with that slideable solutions is they go on other widgets(to left widgets of listview). I found a batter solution here someone wrote a nice article medium and GitHub sample is here.
I look at a lot of articles and answers, and find #Rémi Rousselet answer the best fitted to use without third party libraries.
Just put some improvements to #Rémi's code to make it usable in modern SDK without errors and null safety.
Also I smooth a little bit movement, to make the speed of buttons appeared the same as finger movement.
And I put some comments into the code:
import 'package:flutter/material.dart';
class SlidebleList extends StatefulWidget {
const SlidebleList({Key? key}) : super(key: key);
#override
State<SlidebleList> createState() => _SlidebleListState();
}
class _SlidebleListState extends State<SlidebleList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: ListTile.divideTiles(
context: context,
tiles: List.generate(42, (index) {
return SlideMenu(
menuItems: <Widget>[
Container(
color: Colors.black12,
child: IconButton(
icon: const Icon(Icons.more_horiz),
onPressed: () {},
),
),
Container(
color: Colors.red,
child: IconButton(
color: Colors.white,
icon: const Icon(Icons.delete),
onPressed: () {},
),
),
],
child: const ListTile(
title: Text("Just drag me"),
),
);
}),
).toList(),
),
);
}
}
class SlideMenu extends StatefulWidget {
final Widget child;
final List<Widget> menuItems;
const SlideMenu({Key? key,
required this.child, required this.menuItems
}) : super(key: key);
#override
State<SlideMenu> createState() => _SlideMenuState();
}
class _SlideMenuState extends State<SlideMenu> with SingleTickerProviderStateMixin {
late AnimationController _controller;
#override
initState() {
super.initState();
_controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 200));
}
#override
dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
//Here the end field will determine the size of buttons which will appear after sliding
//If you need to appear them at the beginning, you need to change to "+" Offset coordinates (0.2, 0.0)
final animation =
Tween(begin: const Offset(0.0, 0.0),
end: const Offset(-0.2, 0.0))
.animate(CurveTween(curve: Curves.decelerate).animate(_controller));
return GestureDetector(
onHorizontalDragUpdate: (data) {
// we can access context.size here
setState(() {
//Here we set value of Animation controller depending on our finger move in horizontal axis
//If you want to slide to the right, change "-" to "+"
_controller.value -= (data.primaryDelta! / (context.size!.width*0.2));
});
},
onHorizontalDragEnd: (data) {
//To change slide direction, change to data.primaryVelocity! < -1500
if (data.primaryVelocity! > 1500)
_controller.animateTo(.0); //close menu on fast swipe in the right direction
//To change slide direction, change to data.primaryVelocity! > 1500
else if (_controller.value >= .5 || data.primaryVelocity! < -1500)
_controller.animateTo(1.0); // fully open if dragged a lot to left or on fast swipe to left
else // close if none of above
_controller.animateTo(.0);
},
child: LayoutBuilder(builder: (context, constraint) {
return Stack(
children: [
SlideTransition(
position: animation,
child: widget.child,
),
AnimatedBuilder(
animation: _controller,
builder: (context, child) {
//To change slide direction to right, replace the right parameter with left:
return Positioned(
right: .0,
top: .0,
bottom: .0,
width: constraint.maxWidth * animation.value.dx * -1,
child: Row(
children: widget.menuItems.map((child) {
return Expanded(
child: child,
);
}).toList(),
),
);
})
],
);
})
);
}
}
i had the same problem and and as the accepted answer suggests, i used flutter_slidable
but i needed a custom look for the actions and also i wanted them to be vertically aligned not horizontal.
i noticed that actionPane() can take a list of widgets as children not only
SlidableAction.
so i was able to make my custom actions,and wanted to share the code and results with you here.
this is the layout
this is the code i used :
ListView.builder(
itemBuilder: (context, index) {
return Slidable(
startActionPane: ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.25,
// A pane can dismiss the Slidable.
// All actions are defined in the children parameter.
children: [
Expanded(
flex: 1,
child: Card(
margin: const EdgeInsets.symmetric(
horizontal: 8, vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: [
Expanded(
child: InkWell(
child: Container(
width: double.infinity,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(Icons.edit,
color:
Colors.deepPurple),
Text(
LocalizationKeys.edit.tr,
style: TextStyle(
color:
Colors.deepPurple,
fontSize: 16),
),
],
),
),
onTap: () {},
),
),
Container(
height: 1,
color: Colors.deepPurple,
),
Expanded(
child: InkWell(
child: Container(
width: double.infinity,
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
Icon(Icons.delete,
color: Colors.red),
Text(
LocalizationKeys
.app_delete.tr,
style: TextStyle(
color: Colors.red,
fontSize: 16),
),
],
),
),
onTap: () {},
),
),
],
),
),
),
]),
child: Card(
margin: EdgeInsets.all(16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 16),
Text(_lecturesViewModel
.lectures.value[index].centerName),
SizedBox(height: 16),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(_lecturesViewModel
.lectures.value[index].classLevel),
Text(_lecturesViewModel
.lectures.value[index].material),
],
),
SizedBox(height: 16),
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.location_pin),
Text(_lecturesViewModel
.lectures.value[index].city),
Text(_lecturesViewModel
.lectures.value[index].area),
],
),
SizedBox(height: 16),
Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Icon(Icons.calendar_today),
Text(_lecturesViewModel
.lectures.value[index].day),
],
),
Container(
height: 1,
width: 60,
color: Colors.black,
),
Column(
children: [
Icon(Icons.punch_clock),
Text(_lecturesViewModel
.lectures.value[index].time),
],
),
Container(
height: 1,
width: 60,
color: Colors.black,
),
Column(
children: [
Icon(Icons.money),
Text(
"${_lecturesViewModel.lectures.value[index].price.toString()}ج "),
],
)
]),
SizedBox(height: 16),
]),
),
);
},
itemCount: _lecturesViewModel.lectures.length,
physics: BouncingScrollPhysics(),
)

Categories

Resources