Flutter. Is it possible somehow decorate SliverList/SliverGrid? - flutter

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,
)
),
],
),

Related

Flutter: Add some widgets in between ListView.builder and ScrollView without using shrinkWrap

Is it possible to add some non constrained widgets in between ListView.builder and ScrollView without using shrinkWrap: true? I need something like this:
SingleChildScrollView(
child: Padding(
padding: somePadding,
child: Center(
child: ConstrainedBox(
constraints: someConstaints,
child: Card(
ListView.builder(someBuilder);
),
),
),
),
);
And I can make it with shrinkWrap: true to get something like this:
image of that I'm trying to achieve
The list is inside a centered Card and both the card and the list are scrolled as the whole Scaffold body.
The problem is, the list is expected to be really large so shrinkWrap will have noticeable effect on performance. Is there any way to achieve the same without loosing lazy building of the list?
You should use silvers to overcome this problem and also using silvers instead of shrinkwrap enhances performance of app
Managed to do something close to that I've wanted with Slivers. It's easy to change ScrollView to CustomScrollView and ListView.builder to SliverList with SliverChildBuilderDelegate, the problem is that everything in between should be Slivers as well.
Padding is easy as it has its Sliver counterpart SliverPadding.
Center and ConstrainedBox are more difficult as they seem not to have any Sliver alternatives. So I ended up achieving their effect by using LayoutBuilder (SliverLayoutBuilder is also an option) and manually calculating horizontal padding based on the viewport size and the list width I want.
No solution for Card surrounding the whole list though, so instead I ended up using separate Card for each list child.
So in the end I get something like this:
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return CustomScrollView(
slivers: [
SliverPadding(
padding: EdgeInsets.symmetric(
vertical: somePadding,
horizontal: (constraints.maxWidth - desiredListWidth) / 2),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(/*some list child with card code*/),
),
),
],
);
},
);
It works, but not exactly that I wanted and it has some limitations. So I'm still hoping someone has a more elegant solution.

dynamically switch scroll physics form never scroll to scroll

The title might not be totally accurate but forgive me I don't really know what to write. I am trying to create an effect where a noScroll phyicas Listview that is nested with other elements in a SingleChildScrollView, would need to change to a scrollable physics when it reaches the top of the SingleChildScrollView (thus occupying the whole view) in order to utilize the lazy loading of items.
I must say I ma trying to avoid rebuilding the nested Listview because of that cost and especially the cost of building it with the NeverScrolling physics since that would stall the main UI thread until all items are built.
The necessity of using the NeverScrolling physics in the first place it to allow the SingleChildScrollView to properly scroll (if the list view is set to normal scrolling, the SingleChildScrollView will not be able to scroll if the gesture is coming from the nested Listview)
My code looks like this :
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Material(
child: Container(
child: Column(
children: <Widget>[
ItemListDevider(),
Container(
height: 120,
child: Container(height:120)
),
ItemListDevider(),
Flexible(
fit: FlexFit.loose,
child: THeWidgetHoldingTheListView(album),
)
],
),
),
),
)
// the build method of the THeWidgetHoldingTheListView widget would return this :
Container(
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Flexible(
child: ListView.builder(
controller: controller,
shrinkWrap: true,
itemExtent: FixedItemExtent,
physics: AlwaysScrollableScrollPhysics(),
itemCount: FixedItemCount,
itemBuilder: (context, index) {
return MyCard()
},
),
),
],
),
),
MyScrollbar(
controller: controller,
),
],
),
)
*Note: * I had the idea of creating a custom ScrollPhysics that starts as a NeverScrollPhysics and the switches on a certain scroll offset but that wouldn't change the fact that I have to load the entire list as a Neverscroll and thus stalling the main UI thread.
Is there a way to get around this change of scroll physics, if not how can I implement it without compromising on performance like mentioned above.

Persistent draggable bottom sheet in 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),
));
},
),
);
},
),
),
],),

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),
...
)
)

How do I implement this in Flutter?

I have tried BottomNavigationBar but it requires an Icon.
This instead is text only, sort of represents analytics history and it's scrollable.
For the bottom bar you could make your own custom widget like this:
Container(
height: 80.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: List.generate(10, (int index) {
return new Text("$index");
}),
),
),
Replace the children with actual children that you want for the ListView and adjust its wrapping to have a height that suits your need and there you go