Persistent draggable bottom sheet in Flutter - flutter

I'm using Rubber library at the moment, do you know an approach without using 3rd parts libraries?
The Bottom Sheet must be persistent (not dismissable, not triggered by any button instead, always displayed) and draggable (It must be expanded and collapsed by dragging gestures)

Perhaps DraggableScrollableSheet could work?
I haven't yet tried it out myself, but maybe you could fiddle with a listview to make it work.
I'm guessing something like having it's child be a listview, and then limit both the max child size and the maximum scroll extent

If you do not care that the bottom sheet must snap to different positions you can use the widget from the following package (snapping_sheet) I made.
Or, if you do not want to use it as a 3rd part library, you can copy the code and use it as your own widget from repository here: Github - Snapping sheet

Use DraggableScrollableSheet. Here's an example:
Stack(
children: [
Container(), //the page under the DraggableScrollableSheet goes here
Container(
height: MediaQuery.of(context).size.height,
child: DraggableScrollableSheet(
builder: (BuildContext context, myscrollController) {
return Container(
color: Colors.blue,
child: ListView.builder(
controller: myscrollController,
itemCount: 40,
itemBuilder:(BuildContext context, int index) {
return ListTile(title: Text('Item $index',
style: TextStyle(color: Colors.black),
));
},
),
);
},
),
),
],),

Related

Flutter. Is it possible somehow decorate SliverList/SliverGrid?

I need to make a scrollable for all content for partiular page, but the problem is that I need to have dynamic list at the middle, which grows. So I use CustomScrollView. From top to bottom at slivers[] I have SliverToBoxAdapter decorated as I need, then SliverList and then another one SliverToBoxAdapter. This totaly what I need it is scrollable all together, byt decoration problem with SliverList. So i need to wrap somehow SliverList with the same style so it looks like content inside SliverToBoxAdapter (Borders, evevation, background etc). But I cant understand how to achieve this. The CustomScrollView accepts only Slivers..
I tried to put List inside SliverToBoxAdapter but it scrolls separately or...
Ive solved it but I think in comletely wrong way, with wrapShrink to True, but the Docs day it is very expensive.. And also weird because i moreover need to block scroll Physics with NeverScrollableScrollPhysics(). So looking for better solution
Maybe I do not need to use Slivers?
The general problem is I need vertically lets say Container then List (growable) and then another Container under the list, no matter how long the list are.
Like this
container
List with ability to
dynamically grow when user
taps button
Container strongly under
the List with button
by tapping which user add
the element to the List
Any solutions, ideas, advices ...
Thanks for attention)
Code for sake of simplicity
The BoxAdapter and SliverList
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Center(
child: Container(
child: Column(
children: [
Characteristics(),
],
),
),
),
),
// this is how I have done
// but do not like not lazy..
// if put SliverList directly cant decorate it..
SliverToBoxAdapter(
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (contex, index){
return Container(
alignment: Alignment.center,
color: Colors.teal[100 * (index % 9)],
child: Text('Grid Item $index'),
);
},
itemCount: 20,
)
),
],
),

Keep button fixed in the bottom of screen, but only when the above list height is shorter than the device height

I am developing a Flutter app and would like to keep my button always in the bottom of the screen UNLESS what is in top of it is high enough to make the screen scroll. Examples:
Example A (what is on top of the button does not have height enough to scroll the screen)
Example B (what is on top of the button has height enough to scroll the screen, so the button will just go offscreen and allow the screen to scroll)
So summarizing: the button should be forced to stay at the bottom of the screen when the rest of the list is shorter than the device height, but if the list height is greater than the device height the button should behave normally and stay below the list.
What I tried:
Using a ListView, which will normally scroll if necessary, but I couldn't find a way to send the button to the botton of the screen;
Using a Column. With the help of a Spacer I could make the button go to the bottom of the screen, but a Column will not scroll, and if I add a SingleChildScrollViewto wrap it, the Spacer will no longer work because SingleChildScrollView has the potential to have infinite height;
Thanks.
I got it. The right way of doing this is using LayoutBuilder, ConstrainedBox, IntrinsicHeight and Expanded, like this:
(In this example, _widgets is a list of widgets that I want it to be on top. _buttons is a list of buttons that I want to be in the bottom)
return Scaffold(
appBar: buildAppBar(),
body: LayoutBuilder(
builder: (BuildContext context, BoxConstraints viewportConstraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: IntrinsicHeight(
child: Column(
children: <Widget>[
Expanded(
child: Column(
children: _widgets,
),
),
Column(
children: _buttons,
)
],
),
),
),
);
},
),
);
The documentation says to avoid this, though, as it can be expensive. You can read more about this solution and other details in the documentation.
Stack(
children:[
//Use list widget,
yourList.length<7? Postioned(
bottom :10, margin from bottom
child: //button widget):Container()
])
In listbuilder
ListView.builder(
physics: ScrollPhysics(),
itemCount: yourList+1,
itemBuilder: (BuildContext ctxt, int index) {
if (index== yourList.length) {
return yourList.length >7? //your button widget:Container();
} else {
return //list item}
});

I need your help to in flutter list view section

I have simplified this question please have a look :---
How can I add OnTap event,ICONS & TITLES to below List view code
ListView.builder(
padding: EdgeInsets.all(10.0),
shrinkWrap: false,
itemCount: 200,
itemBuilder: (BuildContext context, int index) {
return listItem(context, index);
},
Widget listItem(BuildContext context, int index) {
return Card(
child: Row(
children: <Widget>[
Container(margin: EdgeInsets.all(10),child: Text("1")),
Container(height: 20,width: 1,color: Colors.blue,),
Container(margin:EdgeInsets.all(10),child: Text("ram ram ram"))
],
),
);
}
Consider changing your Containers with ListTiles, check out the documentation on ListTile. It has an onTap parameter that you can set in order to trigger a function when a ListTile is tapped, and it also has leading, title, and subtitle parameters, where you can pass the icons and titles you need.
Another way of adding onTap detector to any widget is wrapping it with a GestureDetector, or an InkWell, which is basically a GestureDetector with animations and color effects, roughly speaking. Both GestureDetector and InkWell have onTap parameters that you can use to detect taps and trigger functions.

Nested ScrollView inside Slidable panel widget

I have a panel widget that can be dragged vertically in and out from the bottom of the screen. In that panel widget, there is a ListView that is scrollable.
What I'm trying to achieve is, having the panel handle the drag for opening and closing without the nested listview interfering. Once, the panel is open, the listview become scrollable and if the listview is scrolled down while already at the top, the panel handle the gesture instead and closes.
Like so:
I tried to enable/disable scrolling physics on the ListView based on the Panel position but turned out not to be possible that way.
Any ideas ? :)
You can achieve that with DraggableScrollableSheet.
Here is a quick example of how you can use it:
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Center(child: Text('Some content')),
DraggableScrollableSheet(
minChildSize: 0.2,
initialChildSize: 0.2,
builder: (context, scrollController) => Container(
color: Colors.lightBlueAccent,
child: ListView.builder(
controller: scrollController,
itemCount: 20,
itemBuilder: (context, index) => SizedBox(
height: 200,
child: Text('Item $index'),
),
),
),
),
],
),
);
}

How can I add extra bottom spacing in ListView?

When using FloatingActionButton in conjunction with a ListView, it hides part of the UI of the ListView entries, as seen in the screenshot.
Is there a way to automatically add extra spacing at the bottom of a ListView so that the + button does not hide any content?
Assuming you are using ListView, there is a very nice and simple solution to this.
You probably do not want to add padding around the ListView itself as that would make some area of your UI unused.
ListView has apadding parameter for exactly this use case. You can essentially add some padding to the bottom of your ListView that is part of the scrollable area. This means that you will only start seeing this padding once you have scrolled all the way to the bottom. This will allow you to drag the last few items above the FloatingActionButton.
To find an appropriate value for the padding, you can make use of kFloatingActionButtonMargin and _kExtendedSizeConstraints, which is not accessible, thus, I will just use 48 like this.
This means that you will want to add the following to your ListView:
ListView(
padding: const EdgeInsets.only(bottom: kFloatingActionButtonMargin + 48),
..
)
Here is a working example:
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(
home: Scaffold(
body: ListView.builder(
padding: const EdgeInsets.only(bottom: kFloatingActionButtonMargin + 48),
itemCount: 23,
itemBuilder: (context, index) => ListTile(
trailing: Text('$index'),
)),
floatingActionButton: FloatingActionButton(
onPressed: () {},
),
)));
}
Expandable(
ListView.builder(
...
padding: EdgeInsets.only(bottom: 200),
...
)
)