how to enable scrolling when ListView widget reach at top in flutter - flutter

To explain what I want I have created a simple demo file
Here I have 4 container,
What I want is, when I scroll up ,all three container( RED, GREEN and listview) should be scrolled up and when listview reach at top (below welcome container) its scrolling should be start...
class HomeScreen extends StatelessWidget {
HomeScreen({Key? key}) : super(key: key);
List<String> mydata = [];
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
//this welcome container should be fixed at top
Container(height: 50, child: Center(child: Text('Welcome'))),
Container(
height: 100,
color: Colors.red,
),
Container(
height: 200,
color: Colors.green,
),
Expanded(
child: ListView.builder(
itemCount: mydata.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(mydata[index]),
leading: CircleAvatar(),
);
}))
],
),
),
);
}
}

You can increase the itemCount by two.
body: SafeArea(
child: Column(
children: [
Container(height: 50, child: Center(child: Text('Welcome'))),
Expanded(
child: ListView.builder(
itemCount: mydata.length + 2,
itemBuilder: (context, index) {
if (index == 0) {
return Container(
height: 100,
color: Colors.red,
);
}
if (index == 1) { // you can just merge it with if like `index<2`, then use condition
return Container(
height: 200,
color: Colors.green,
);
}
return ListTile(
title: Text(mydata[index - 2]),
leading: CircleAvatar(),
);
}))
],
),
),
Also I will suggest you to check CustomScrolView.

Related

Use ListView horizontal like Tabview with flutter

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 am not able to make my app scrollble, despite of having SingleChildScrollView in Flutter

In my app, i have used BlogTile and CategoryTile widgets (which were made by myself) and I am using them in Contaniers/Columns. When I used SingleChildScrollView with CategoryTile, and made axis as horizontal, it was working fine. But as soon as i use it for BlogTile, it doen't work. I am not able to scroll in my app vertically. But when i try to scroll vertically by clicking on the part between CategoryTile and BlogTile, it works. But when i try to scroll by clicking from anyb other section of it, it doesn't work. Please someone help me
Check this code -
import 'package:flutter/material.dart';
import 'package:news_app/helper/data.dart';
import 'package:news_app/helper/news.dart';
import 'package:news_app/models/article_model.dart';
import 'package:news_app/models/category_models.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
List<CategoryModel> categories = new List<CategoryModel>();
List<ArticleModel> articles = new List<ArticleModel>();
bool loading = true;
#override
void initState() {
// TODO: implement initState
super.initState();
categories = getCategories();
getNews();
}
getNews() async {
News newsClass = News();
await newsClass.getNews();
articles = newsClass.news;
setState(() {
loading = false;
print('Done');
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Flutter',
style: TextStyle(
color: Colors.black,
),
),
Text(
'News',
style: TextStyle(
color: Colors.blue,
),
),
],
),
//elevation: 2.0,
),
body: loading
? Center(
child: Container(
child: CircularProgressIndicator(),
),
)
: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(top: 10.0),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
///Categories
Container(
padding: EdgeInsets.symmetric(horizontal: 16.0),
height: 70.0,
child: ListView.builder(
itemCount: categories.length,
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (context, index) {
return CategoryTile(
imageUrl: categories[index].imageUrl,
categoryName: categories[index].categoryName,
);
},
),
),
SizedBox(
height: 30.0,
),
///Blogs
SingleChildScrollView(
child: Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: articles.length,
itemBuilder: (context, index) {
return BlogTile(
imageUrl: articles[index].urlToImage,
title: articles[index].title,
desc: articles[index].description,
);
},
),
),
),
],
),
),
),
),
),
),
);
}
}
class CategoryTile extends StatelessWidget {
final imageUrl, categoryName;
CategoryTile({this.imageUrl, this.categoryName});
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {},
child: Container(
margin: EdgeInsets.only(right: 16.0),
child: Stack(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(6.0),
child: Image.network(
imageUrl,
width: 120.0,
height: 160.0,
fit: BoxFit.cover,
),
),
Container(
alignment: Alignment.center,
width: 120.0,
height: 160.0,
decoration: BoxDecoration(
color: Colors.black26,
borderRadius: BorderRadius.circular(6.0)),
child: Text(
categoryName,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w500,
fontSize: 14.0,
),
),
),
],
),
),
);
}
}
class BlogTile extends StatelessWidget {
final String imageUrl, title, desc;
BlogTile(
{#required this.imageUrl, #required this.desc, #required this.title});
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Image.network(imageUrl),
Text(title),
Text(desc),
],
),
);
}
}
I think the issue here is that you're giving unbounded height and width to some of the ScrollViews.
First off, don't use multiple scrolling widgets nested inside one another. But if you want to do that, try wrapping each of your scrollview within a Container like this:
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
height: 50.0,
width: 50.0,
child: SingleChildScrollView(
child: ...,
),
),
),
What I'd also suggest is that instead of using a SingleChildScrollView, use a ListView widget. It works almost the same and you can put multiple children inside it. A simple ListView() will work. Don't use ListView.builder or any other aggregate function.

Items in ListView get it's height

I'm trying to create a horizontal list view with some card.
I want the list view to have height X and the cards to have height Y, I don't know why but the cards are getting the height of the list view.
This is what I have:
class FinanceApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Container(
color: Color(0x180000),
child: Column(
children: <Widget>[
Header(),
SizedBox(
height: 20,
),
Expanded(
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32.0),
topRight: Radius.circular(32.0),
),
),
child: Column(
children: <Widget>[
Container(
height: 250,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
CustomCard(),
CustomCard(),
],
),
),
],
),
),
),
],
),
),
),
);
}
}
EDIT: The only thing that kinda works for me, Is to wrap the card container in another container, use padding to get the size I want, but it does not seem like a great solution.
Check this out:
import 'package:flutter/material.dart';
class StackOverFlow extends StatefulWidget {
#override
_StackOverFlowState createState() => _StackOverFlowState();
}
class _StackOverFlowState extends State<StackOverFlow> {
#override
Widget build(BuildContext context) {
return Scaffold(
body:
Center(
child: Container(
color: Colors.blue,
height: 200.0,
width: double.infinity,
child: ListView.builder(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(16.0),
itemCount: 100,
itemBuilder: _buildItem,
),
),
),
);
}
Widget _buildItem (BuildContext context, int index) {
return Center(
child: Card(
child: Text(index.toString()),
),
);
}
}
And for giving children same size consider wrapping the cards with a Container:
Widget _buildItem (BuildContext context, int index) {
return Center(
child: Container(
height: 100.0,
width: 100.0,
child: Card(
child: Center(child: Text(index.toString())),
),
),
);
}

Flutter : Listview Builder Horizontal Inside Stack Widget

I have design like above, In that design I implement to app. I have Stack Widget inside container then inside Stack widget i have ListviewBuilder with Scroll direction Horizontal.
But the problem is, I cant scroll ListViewBuilder Horizontal inside Stack widget.
How can i fixed this ?
My Trial Fail
Source Code
class HomeScreen extends StatelessWidget {
static const routeName = "/home-screen";
#override
Widget build(BuildContext context) {
final mqHeight = MediaQuery.of(context).size.height;
final mqWidth = MediaQuery.of(context).size.width;
return SafeArea(
child: Scaffold(
appBar: AppBar(
elevation: 0,
title: Text('Good Morning'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () => "",
)
],
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
height: mqHeight / 3,
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
color: Colors.red,
),
Positioned(
top: mqHeight / 4.5,
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)
],
),
),
Container(
child: Text(
'data data data data data data data data data ',
style: Theme.of(context).textTheme.display4,
),
)
],
)),
),
);
}
}
You can copy paste run full code below
From https://github.com/flutter/flutter/issues/36584#issuecomment-554950474
Add top, right, bottom attribute
code snippet
Positioned(
top: mqHeight / 4.5,
left:0.0,
right:0.0,
bottom:0.0,
child: SizedBox(
height: 100,
child: ListView.builder(
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,
),
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
static const routeName = "/home-screen";
#override
Widget build(BuildContext context) {
final mqHeight = MediaQuery.of(context).size.height;
final mqWidth = MediaQuery.of(context).size.width;
return SafeArea(
child: Scaffold(
appBar: AppBar(
elevation: 0,
title: Text('Good Morning'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () => "",
)
],
),
body: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
color: Colors.blue,
height: mqHeight / 3,
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Container(
color: Colors.red,
),
Positioned(
top: mqHeight / 4.5,
left:0.0,
right:0.0,
bottom:0.0,
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)
],
),
),
Container(
child: Text(
'data data data data data data data data data ',
style: Theme.of(context).textTheme.display4,
),
)
],
)),
),
);
}
}
I have already fixed as below:
Positioned(
top: mqHeight / 4.5,
left: 0, /// <-- fixed here
right: 0, /// <-- fixed here
child: SizedBox(
height: 100,
child: ListView.builder(
physics: ClampingScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 20,
itemBuilder: (BuildContext context, int index) {
return Container(
width: 100,
child: Card(
elevation: 10,
child: Icon(Icons.card_giftcard)),
);
},
),
),
)```

How to avoid other stack containers?

I have a chat widget that I've been having trouble with given the unique header. Finally figured out how to position the TextComposer at the base of the app and all looks great, however the ListView where the chat's occur overlaps the header after a certain number of text entries. I've been trying to figure out how to position the ListView.builder so that it stays below the header (_buildImage and _buildTopHeader) and doesn't overlap such as in the image below. Unfortunately I haven't been having any luck. Any suggestions would be greatly appreciated!
Thanks!
Header Overlap
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: Stack(children: <Widget>[
_buildIamge(),
_buildTopHeader(),
Container(
alignment: Alignment.center,
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
]),
),
Container(
decoration:
new BoxDecoration(color: Theme.of(context).cardColor),
height: 50.0,
child: _buildTextComposer(),
alignment: Alignment.bottomCenter,
),
],
),
),
resizeToAvoidBottomPadding:false,
);
}
Stack renders its children list in order from top to bottom, with stuff on the bottom rendered over things at the top (it makes sense, I promise). So if you want the ListView to be rendered at the bottom of everything else, put it at the top of the children list:
Stack(
children: <Widget>[
Container(
alignment: Alignment.center,
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
),
),
_buildIamge(),
_buildTopHeader(),
],
),
Take a try with Positioned
Demo:
import 'package:flutter/material.dart';
class StackPositionPage extends StatefulWidget {
StackPositionPage({Key key, this.title}) : super(key: key);
final String title;
#override
_StackPositionPageState createState() => _StackPositionPageState();
}
class _StackPositionPageState extends State<StackPositionPage> {
var _headerHeight = 100.0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: buildBody(context),
);
}
Widget buildBody(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: Stack(children: <Widget>[
_buildIamge(),
_buildTopHeader(),
Positioned(
top: _headerHeight,
left: 0,
right: 0,
bottom: 0,
child: ListView.builder(
padding: new EdgeInsets.all(8.0),
itemBuilder: (_, int index) => Padding(
padding: const EdgeInsets.all(16.0),
child: _buildMessage(index),
),
),
),
]),
),
Container(
color: Colors.blue,
height: 50.0,
alignment: Alignment.bottomCenter,
child: Center(
child: Text("Composer"),
),
),
],
),
);
}
Text _buildMessage(int index) => Text("Message " + (index + 1).toString());
Container _buildTopHeader() {
return Container(
height: _headerHeight,
color: Colors.pink,
child: Center(
child: Text("Header"),
),
);
}
Container _buildIamge() {
return Container(
color: Colors.grey,
);
}
}