How to have a nested SliverList in Flutter? - flutter

I am using a SliverAppBar and SliverList inside a CustomScrollView. Now I want to build a another ListView inside the SliverList I have. But it doesn't let me.

You will need a NestedScrollView
Here's an example:-
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: SliverAppBar(),
body: new NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
new SliverAppBar(
pinned: true,
title: new Text('Flutter Demo'),
),
];
},
body: new Column(
children: <Widget>[
new FlutterLogo(size: 100.0, colors: Colors.purple),
new Container(
height: 300.0,
child: new ListView.builder(
itemCount: 60,
itemBuilder: (BuildContext context, int index) {
return new Text('Item $index');
},
),
),
new FlutterLogo(size: 100.0, colors: Colors.orange),
],
),
),
);
}
}

Related

Weird space between SliverAppBar and ListView in flutter

I wrote a NestedScrollView interface in the example of the Flutter document, but when I look at the ListView as the body, I find that there is a weird gap between the ListView and the SliverAppBar. What can I do to delete this gap
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, boxIsScrolled) {
return [
SliverAppBar(
pinned: true,
expandedHeight: 100,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: Container(
color: Colors.red,
),
),
),
];
},
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
child: Text(
"$index",
),
color: Colors.green,
);
},
),
),
);
}
}
You can wrap your Listview with the MediaQuery. There is one method for remove unwanted space. You can check below code.
MediaQuery.removePadding(
removeTop: true,
context: context,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
child: Text(
"$index",
),
color: Colors.green,
);
},
),
)

Flutter adding NestedScrollView into SliverChildListDelegate and getting RenderFlex error

in my application i have a CustomScrollView which with that i can have a auto Hide AppBar
UPDATE
SAMPLE CODE ADDED
CustomScrollView(
controller: _scrollController,
physics: const ClampingScrollPhysics(),
slivers: <Widget>[
SliverFeedsList(),
],
);
inside SliverFeedsList i want to have another SliverList and SliverPersistentHeader.
when i'm adding them i get this error:
RenderFlex children have non-zero flex but incoming height constraints are unbounded.
Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible children
(using Flexible rather than Expanded).
This will allow the flexible children to size themselves to
less than the infinite remaining space they would otherwise be forced to take,
and then will cause the RenderFlex to shrink-wrap the children rather than expanding to fit the maximum constraints provided by the parent.
SliverFeedsList partial content:
Column(
children: [
Expanded(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return Column(
children: <Widget>[
Container(
color: Colors.pink,
height: 50.0,
),
Container(
color: Colors.yellow,
height: 50.0,
)
],
);
}, childCount: 1),
),
SliverPersistentHeader(
pinned: true,
floating: true,
delegate: CustomTabHeader(
Container(
color: Colors.pink,
height: 50.0,
)
),
),
];
},
body: ListView.builder(
itemCount: 10,
padding: const EdgeInsets.only(top: 8),
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return Container(height: 36.0, child: Text('aaa'));
},
),
),
),
],
)
sample code for text and troubleshooting that
void main() => runApp(NestedSliverContainer());
class NestedSliverContainer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Custom Nested Sliver',
home: MyNestedSliverContainerApp(),
);
}
}
class MyNestedSliverContainerApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: CustomScrollView(
physics: const ClampingScrollPhysics(),
slivers: <Widget>[
SliverPadding(
padding: const EdgeInsets.all(0),
sliver: SliverList(
delegate: SliverChildListDelegate([
Column(
children: [
Expanded(
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return Column(
children: <Widget>[
Container(
color: Colors.pink,
height: 50.0,
),
Container(
color: Colors.yellow,
height: 50.0,
)
],
);
}, childCount: 1),
),
SliverPersistentHeader(
pinned: true,
floating: true,
delegate: CustomTabHeader(Container(
color: Colors.pink,
height: 50.0,
)),
),
];
},
body: ListView.builder(
itemCount: 10,
padding: const EdgeInsets.only(top: 8),
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return Container(height: 36.0, child: Text('test'));
},
),
),
),
],
)
]),
),
)
],
),
),
);
}
}
class CustomTabHeader extends SliverPersistentHeaderDelegate {
CustomTabHeader(
this.searchUI,
);
final Widget searchUI;
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return searchUI;
}
#override
double get maxExtent => 52.0;
#override
double get minExtent => 52.0;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}
I guess, it doesn't need to be nested . Keep it flat.
import 'package:flutter/material.dart';
void main() => runApp(NestedSliverContainer());
class NestedSliverContainer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Custom Nested Sliver',
home: MyNestedSliverContainerApp(),
);
}
}
class MyNestedSliverContainerApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Column(
children: <Widget>[
Container(
color: Colors.pink,
height: 50.0,
),
Container(
color: Colors.yellow,
height: 50.0,
)
],
);
}, childCount: 1),
),
SliverPersistentHeader(
pinned: true,
floating: true,
delegate: CustomTabHeader(Container(
color: Colors.pink,
height: 50.0,
)),
),
];
},
body: ListView.builder(
itemCount: 10,
padding: const EdgeInsets.only(top: 8),
scrollDirection: Axis.vertical,
itemBuilder: (BuildContext context, int index) {
return Container(height: 36.0, child: Text('test'));
},
),
),
),
);
}
}
class CustomTabHeader extends SliverPersistentHeaderDelegate {
CustomTabHeader(
this.searchUI,
);
final Widget searchUI;
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return searchUI;
}
#override
double get maxExtent => 52.0;
#override
double get minExtent => 52.0;
#override
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return false;
}
}

How to prevent widget from beeing scrolled?

How to prevent the first widget (ListView) from beeing scrolled?
The idea is to scroll SomeList, but the most top ListView widget should remain unscrollable.
body: ListView(
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
ListTile( // how to prevet this widget from beeing scrolled?
title: Container(
height: 30,
child: Row(...),
),
),
],
),
SomeList(), // builds ListView.separated( ...
],
),
updated:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', home: MyListView());
}
}
class MyListView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar'),
),
body: ListView(
children: <Widget>[
ListView(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
ListTile(
title: Container(
height: 30,
color: Colors.black45,
child: Row(
children: const <Widget>[
Expanded(child: Text('Some header')),
],
),
),
),
],
),
RapportList(),
],
),
);
}
}
class RapportList extends StatefulWidget {
#override
_RapportListState createState() => _RapportListState();
}
class _RapportListState extends State<RapportList> {
#override
Widget build(BuildContext context) {
return ListView.separated(
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: 100,
itemBuilder: (context, index) {
return ListTile(
title: Row(
children: <Widget>[
Expanded(child: Text('$index')),
],
),
);
},
separatorBuilder: (context, index) {
return const Divider();
},
);
}
}
Solution is with Expended Widget,
use physics: NeverScrollableScrollPhysics(), too. here is full code:
class MyListView extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('AppBar'),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: <Widget>[
Expanded(
flex:1,
child: ListView(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
children: <Widget>[
ListTile(
title: Container(
height: 30,
color: Colors.black45,
child: Row(
children: const <Widget>[
Expanded(child: Text('Some header')),
],
),
),
),
],
),
),
Expanded(flex:9,child: RapportList()),
],
),
),
);
}
}
Use physics: const NeverScrollableScrollPhysics() in Listview Then you can prevent your widget from beeing scrolled.

Flutter: collapsing app bar with pinned tabBar

How add build collapsing app bar with pinned tabBar in Flutter like in this GIF
I managed to build it like so
class Test extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: DefaultTabController(
length: 2,
child: NestedScrollView(
headerSliverBuilder: (context, value) {
return [
SliverAppBar(
floating: true,
pinned: true,
title: Text('Test'),
bottom: TabBar(
tabs: [
Tab( text: "Call"),
Tab( text: "Message"),
],
),
),
];
},
body: TabBarView(
children: [
Container(child: ListView.builder(
itemCount: 100,
itemBuilder: (context,index){
return Text("Item $index");
})),
Container(child: ListView.builder(
itemCount: 100,
itemBuilder: (context,index){
return Text("Item $index");
})),
],
),
),
),
);
}
}
You can use the SilverAppBar
SliverAppBar(
expandedHeight: 150.0,
floating:true,
pinned: true,
flexibleSpace: const FlexibleSpaceBar(
title: Text('Available seats'),
),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_circle),
tooltip: 'Add new entry',
onPressed: () { /* ... */ },
),
]
)
References
SliverAppBar Class
SliverAppBar Widget of the week
Keep the TabBarView seperate from the SliverAppBar.
Make it look continuous by setting SliverAppBar's elevation to 0 and use shadow or elevation for the TabBarView, whatever you prefer.

Where to define named parameter 'sliver'

So, I am creating a sliver based AppBar based on this example I found, and am facing the error named parameter 'slivers' isn't defined.
My code somewhat looks like this (I know I am probably putting the sliver in the wrong place, but any help in understanding the issue is appreciated).
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.white,
onPressed: () {},
child: Icon(
CommunityMaterialIcons.plus,
color: Colors.black,
),
),
slivers: <Widget>[ // *problematic sliver here*
SliverAppBar(
pinned: true,
expandedHeight: 256.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('po.'),
),
),
],
body: ListView.builder(
itemCount: tracks.length,
itemBuilder: (BuildContext context, int index) { // the rest of the itembuilder continued here
Indeed slivers field is not defined for Scaffold. Wrap your appbar and listview in NestedScrollView like this:
Widget build(BuildContext context) => Scaffold(
backgroundColor: Colors.white,
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.white,
onPressed: () {},
child: Icon(
Icons.plus_one,
color: Colors.black,
),
),
body: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 256.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('po.'),
),
),
];
},
body: ListView.builder(
padding: EdgeInsets.all(8.0),
itemExtent: 20.0,
itemBuilder: (BuildContext context, int index) {
return Text('entry $index');
},
)));
Here is fixed gist you provided:
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
theme: ThemeData.dark(),
debugShowCheckedModeBanner: false,
home: Home(),
));
}
class Home extends StatelessWidget {
final tracks = const [
{'title': 'BCS Examination', 'subtitle': 'Something'},
{'title': 'Dhaka University Admission'},
{'title': 'Khulna University Admission'},
{'title': 'Chottogram University Admission'},
{'title': 'Bank Job Exam'},
{'title': 'Bank Job Exam'}
];
#override
Widget build(BuildContext context) => Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.white,
onPressed: () {},
child: Icon(
Icons.info,
color: Colors.black,
),
),
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
pinned: true,
expandedHeight: 256.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('po.'),
),
),
];
},
body: ListView.builder(
itemCount: tracks.length,
itemBuilder: (BuildContext context, int index) {
var trackTitles = tracks[index];
return Text(trackTitles['title']);
}),
));
}
In the body you cold set a SliverList and set the child count as 0.
Something like:
SliverList(
delegate: new SliverChildListDelegate(<Widget>[]),
)
Normally I use it with a CustomScrollView but you could try.