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.
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 have a scrolableView with x amount of ExpansionTiles, I need to place the 'Test' button on the bottom of the page, only if a number of tiles are fitting the screen or if they expand within the page, else to push the button off the screen.
import 'package:flutter/material.dart';
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
List datas = [1, 2, 3, 4, 5, 6];
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
ListView.builder(
physics: NeverScrollableScrollPhysics(),
itemCount: datas.length,
shrinkWrap: true,
itemBuilder: (context, i) {
return ExpansionTile(
title: Text(
datas[i].toString(),
),
children: List.generate(
datas.length,
(index) {
return Text(datas[index].toString());
},
));
},
),
ElevatedButton(onPressed: () {}, child: Text('Test'))
],
),
),
),
);
}
}
The UX is a little tricky. It will be easy and get better performance using CustomScrollView.
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: CustomScrollView(
slivers: [
SliverList(
delegate: SliverChildListDelegate.fixed(
[
...datas
.map((e) => ExpansionTile(
title: Text(
e.toString(),
),
children: List.generate(
datas.length,
(index) {
return Text(datas[index].toString());
},
)))
.toList(),
],
),
),
SliverFillRemaining(
hasScrollBody: false,
child: Align(
alignment: Alignment.bottomCenter,
child: ElevatedButton(
onPressed: () {},
child: const Text('Test'),
),
),
)
],
)),
);
}
The important thing is using SliverFillRemaining with hasScrollBody: false along with Align child.
More about CustomScrollView.
The Parent Widget Is Column,
Column Contains the following children:
STACK
CONTAINER(CHILD: ROW)
ROW(CHILDREN: [GESTUREDETECTOR(child:Container), GESTUREDETECTOR(child:Container)]
LISTVIEW BUILDER
Wrapping this column with expanded, and then with singlechildScrollView. The result is the error!!
WHAT TO DO??
Wrap Column with SinglechildScrollView, for ListView.builder you need to set:
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
In your case widget tree will look like this (minimal reproducible sample)
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SingleChildScrollView',
home: Scaffold(
appBar: AppBar(
title: Text('SingleChildScrollView Example'),
),
body: SingleChildScrollView(
child: Column(
children: [
Stack(
children: [
Container(
width: 50,
height: 50,
color: Colors.cyan,
),
],
),
Container(
child: Row(
children: [
GestureDetector(
child: Container(
width: 50,
height: 50,
color: Colors.green,
),
),
GestureDetector(
child: Container(
width: 50,
height: 50,
color: Colors.blue,
),
),
],
),
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: 60,
itemBuilder: (context, index) => Text('Item # $index'),
)
],
),
)),
);
}
}
And it scrolls.
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"));
}),
);
}),
),
),
],
),
);
}),
));
}
}
in this sample code i want to put nested ListView inside SingleChildScrollView, but i get this error:
RenderBox was not laid out: RenderRepaintBoundary#8de00 relayoutBoundary=up1 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'
my code:
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: Scaffold(
appBar: AppBar(
title: Text("Scrollview Demo"),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text('message'),
),
),
Expanded(
child: ListView.builder(
itemCount: 30,
itemBuilder: (context, index) {
return ListTile(title: Text("Index : $index"));
},
),
),
],
),
),
),
);
}
}
In ListView you can set
shrinkWrap: true
so that ListView only occupies the space it needed.
To disable the scrolling on ListView so it uses that of SingleChildScrollView you can set the
physics: NeverScrollableScrollPhysics().
You need to remove the Expanded which set the child to take the available screen in case of here is infinite.
Here:
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text('message'),
),
),
Flexible(
child: ListView.builder(
itemCount: 30,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(title: Text("Index : $index"));
},
),
),
],
),
)
Instead of using SingleChildScrollView then use Column as the child just use ListView.
return Scaffold(
body: ListView(
children: <Widget>[
Container(
height: 104,
child: Card(
clipBehavior: Clip.antiAliasWithSaveLayer,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[],
),
),
),
ListView(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
),
],
),
);
Ones I was in the same situation and did like that:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: Scaffold(
appBar: AppBar(
title: Text("Scrollview Demo"),
),
body: ListView.builder(
itemCount: 30 + 1,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
height: 50.0,
color: Colors.green,
child: Center(
child: Text('message'),
),
);
}
return ListTile(title: Text('Index : ${index -1}'));
},
),
),
);
}
}