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;
}
}
Related
I'm looking for a tutorial on using a horizontal ListView that behaves like a Tabview, ie displaying the link on the same screen.
Some links to propose?
thanks
Tab child can others widget too, use height on Tab and isScrollable:true on TabBar
class TabBarDemo extends StatelessWidget {
const TabBarDemo({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: 3,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
isScrollable: true,
tabs: [
Tab(
height: 100, // height
icon: Card(
child: Container(
height: 100,
width: 100,
color: Colors.red,
),
)),
Tab(
icon: Icon(Icons.directions_transit),
),
Tab(
icon: Icon(Icons.directions_bike),
),
],
),
title: const Text('Tabs Demo'),
),
body: const TabBarView(
children: [
Icon(Icons.directions_car),
Icon(Icons.directions_transit),
Icon(Icons.directions_bike),
],
),
),
),
);
}
}
more about tabs
And using PageView & ListView, it will be
class TabBarDemo extends StatelessWidget {
const TabBarDemo({super.key});
#override
Widget build(BuildContext context) {
final PageController controller = PageController();
return Scaffold(
body: Column(
children: [
SizedBox(
height: 100, //tab item height
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
controller.animateToPage(index,
duration: Duration(milliseconds: 100),
curve: Curves.bounceIn);
},
child: Container(
height: 100,
width: 100,
color: Colors.red,
child: Card(
child: Text("tab $index"),
),
),
),
),
),
Expanded(
child: PageView.builder(
controller: controller,
itemBuilder: (context, index) {
return Center(
child: Text("$index"),
);
},
),
),
],
),
);
}
}
Also you can check CustomScrollView.
run this example and you will get the whole idea :
class ListTapPage extends StatefulWidget {
const ListTapPage({Key? key}) : super(key: key);
#override
State<ListTapPage> createState() => _ListTapPageState();
}
class _ListTapPageState extends State<ListTapPage> {
List<Widget> pages = [const Center(child: Text("one")),const Center(child: Text("two")),const Center(child: Text("three"),)];
List<String> names = ["one","two","three"];
List<Color> colors = [Colors.red,Colors.blue,Colors.yellow];
int _index = 0 ;
void changeIndex({required int num}){
setState((){
_index = num;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Positioned(top: 0,right: 0,left: 0,bottom: MediaQuery.of(context).size.height * 0.75,
child: SizedBox(
height: 100,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 3,
itemBuilder: (context, index) {
return GestureDetector(
onTap:()=>changeIndex(num: index) ,
child: Container(alignment: Alignment.center,width: 200,height: 50,color: colors[index],child: Text(names[index])),
);
},
),
)
),
Positioned(
left: 0,
right: 0,
bottom: 0,
height: MediaQuery.of(context).size.height * 0.30,
child: pages[_index]
),
]
),
),
);
}
}
just return this widget in the material app ,see the result and look at the code , you will understand , it's a simple demo.
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,
);
},
),
)
does anyone know why my draggable scrollable sheet doesn't work or why I can't see it?
I tried it in another way it worked, but I didn't use the SafeArea-Widget,
import 'package:flutter/material.dart';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(100.0),
child: AppBar(
//AppBar
),
body: SafeArea(
child: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
dateday,
style: TextStyle(
color: Color(0xff2C8E5D),
fontSize: 150,
),
),
),
SizedBox.expand(
child: DraggableScrollableSheet(builder:
(BuildContext context, ScrollController scrollController) {
return Container(
color: Colors.red,
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("Item $index"));
}),
);
}),
),
],
),
),
);
}
}
Thanks for your help!
Replace the ListView with a Stack:
body: SafeArea(
child: Stack(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
dateday,
style: TextStyle(
color: Color(0xff2C8E5D),
fontSize: 150,
),
),
),
SizedBox.expand(
child: DraggableScrollableSheet(
builder:
(BuildContext context, ScrollController scrollController) {
return Container(
color: Colors.red,
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("Item $index"));
}),
);
}),
),
],
),
),
You can use LayoutBuilder and BoxConstraints to provide height and use Expanded flex to control DraggableScrollableSheet's scroll area
code snippet
SafeArea(
child: LayoutBuilder(builder: (context, constraints) {
return ConstrainedBox(
constraints: BoxConstraints(maxWidth: constraints.maxWidth),
child: Column(
children: <Widget>[
Expanded(
flex: 1,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
"dateday",
...
Expanded(
flex: 3,
child: SizedBox.expand(
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('DraggableScrollableSheet'),
),
body: SafeArea(
child: LayoutBuilder(builder: (context, constraints) {
print(constraints.maxWidth);
print(constraints.minWidth);
return ConstrainedBox(
constraints: BoxConstraints(maxWidth: constraints.maxWidth),
child: Column(
children: <Widget>[
Expanded(
flex: 1,
child: Padding(
padding: EdgeInsets.only(left: 20),
child: Text(
"dateday",
style: TextStyle(
color: Color(0xff2C8E5D),
fontSize: 150,
),
),
),
),
Expanded(
flex: 3,
child: SizedBox.expand(
child: DraggableScrollableSheet(builder:
(BuildContext context,
ScrollController scrollController) {
return Container(
color: Colors.red,
child: ListView.builder(
controller: scrollController,
itemCount: 25,
itemBuilder: (BuildContext context, int index) {
return ListTile(title: Text("Item $index"));
}),
);
}),
),
),
],
),
);
}),
));
}
}
Having an issue with scrolling when using slivers and a sliver appbar. How can I prevent the scrollview from scrolling when no scroll is needed like in the video. And if there are enough items for scrolling it should scroll (That works perfectly)
I followed this medium post. And you can see that he has the same problem.
https://medium.com/#diegoveloper/flutter-collapsing-toolbar-sliver-app-bar-14b858e87abe
https://youtu.be/l1EwM9GAfxw
class HomeScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverAppBar(
brightness: Brightness.dark,
backgroundColor: Colors.amber.withOpacity(0.5),
expandedHeight: 166,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 80,
width: 80,
child: Placeholder(),
),
Row(
children: [
Text(
'sdalkf',
),
],
),
],
),
),
),
),
SliverPersistentHeader(
delegate: SliverAppBarDelegate(
MediaQuery.of(context).padding.top,
Container(
color: Colors.amber.withOpacity(0.5),
child: SafeArea(
bottom: false,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('sdfaklladsjfkladslkf\nsadjflkasjklfs\nsdkjlfjlkadslfjk'),
],
),
),
),
),
pinned: true,
),
],
body: GridView.builder(
itemCount: 3,
padding: EdgeInsets.zero,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 0.68),
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Container(
color: Colors.black54,
),
),
),
),
);
}
}
class SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final Widget child;
final double topSafeArea;
_SliverAppBarDelegate(this.topSafeArea, this.child);
#override
double get minExtent => 105 + topSafeArea;
#override
double get maxExtent => 105 + topSafeArea;
#override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
return Container(
child: child,
);
}
#override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return false;
}
}
Related to:
Flutter SliverAppBar with Tabs overlays content
The above link is not a sollution but a temp fix
Set physics behavior of ScrollView to AlwaysScrollableScrollPhysics
from documentation:
/// Scroll physics that always lets the user scroll.
///
/// This overrides the default behavior which is to disable scrolling
/// when there is no content to scroll. It does not override the
/// handling of overscrolling.
What is the preferred way to achieve a nested ListView, or in other words, ListView Widgets that could be included within a scrollable parent?
Imagine a "Reports" page, where a section is an itemized list.
For child ListView, use that parameter:
shrinkWrap: true,
physics: ClampingScrollPhysics(),
Adding physics: ClampingScrollPhysics() and shrinkWrap: true did the trick for me.
sample code:
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: 123,
itemBuilder: (BuildContext context, int index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Parent'),
ListView.builder(
itemCount: 2,
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Text('Child');
}),
],
);
}),
)
],
),
);
}
If you want to have the inner ListView be scrollable independently of the main scroll view, you should use NestedScrollView. Otherwise, use a CustomScrollView.
Here is some code illustrating the NestedScrollView approach.
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
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),
],
),
),
);
}
}
For inner Listview I have just added below code and it solved for me
shrinkWrap: true,
physics: ScrollPhysics(),
Screenshot:
Code:
var _container = Container(
height: 200,
color: Colors.blue,
margin: EdgeInsets.symmetric(vertical: 10),
);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ListView")),
body: Padding(
padding: const EdgeInsets.all(40.0),
child: ListView( // parent ListView
children: <Widget>[
_container,
_container,
Container(
height: 200, // give it a fixed height constraint
color: Colors.teal,
// child ListView
child: ListView.builder(itemBuilder: (_, i) => ListTile(title: Text("Item ${i}"))),
),
_container,
_container,
_container,
],
),
),
);
}
Thanks to Serdar Polat:
ListView.builder( // outer ListView
itemCount: 4,
itemBuilder: (_, index) {
return Column(
children: [
Container(
color: Colors.blue,
alignment: Alignment.center,
child: Text('Header $index'),
),
ListView.builder( // inner ListView
shrinkWrap: true, // 1st add
physics: ClampingScrollPhysics(), // 2nd add
itemCount: 10,
itemBuilder: (_, index) => ListTile(title: Text('Item $index')),
)
],
);
},
)
shrinkWrap to wrap your content and ClampingScrollPhysics to use the parent scroll
ListView.builder(
shrinkWrap: true,
physics: const ClampingScrollPhysics(),
itemCount: yourList.length,
itemBuilder: (context, index) => YourWidget(items[index]),
),
I use this:
scrollController.addListener(onScroll);
void onScroll(){
if(scrollController.offset == 0.0
|| scrollController.position.extentBefore == 0.0
|| scrollController.position.extentAfter == 0.0){
scrollPhysics = NeverScrollableScrollPhysics();
Future.delayed(Duration(seconds: 1), (){
scrollPhysics = ClampingScrollPhysics();
setState((){});
});
setState((){});;
}
}
Expanded(
child: ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8),
itemCount: requestList.length,
itemBuilder: (BuildContext context, int index) {
int que = index;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: const EdgeInsets.only(
left: 20,
top: 10,
bottom: 10,
right: 20),
child: Text(
'${que++} . ${requestList[index].question}',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: HexColor(HexColor.black),
fontFamily: 'montserrat_regular',
decoration: TextDecoration.none,
),
)),
ListView.builder(
itemCount: requestList[index].questionOptions!.length,
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int subindex) {
return Row(
children: <Widget>[
Radio(
value: 1,
groupValue: radio_value[index],
onChanged: (values) async {
setState(() {
radio_value[index] = 1;
qutionCheckModel[index].response =
"yes";
});
}),
Container(
child: Text(
requestList[index].questionOptions![subindex],
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
color: HexColor(HexColor.black),
fontFamily: 'montserrat_regular',
decoration: TextDecoration.none,
),
),
),
],
);
}),
],
);
}),
),