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

Related

Drawer with ListViewBuilder and Header in Flutter

I'm trying to make a drawer widget that uses a ListViewBuilder to populate itself based on a list injected into the ViewModel.
However, I'm having issues getting it to play ball.
I've wrapped the LVB in a SizedBox to provide it with vertical bounds (since it was throwing a bunch of errors, as suggeested by another answer, and that's stopped those, but now I'm getting an overflow.
The header also doesn't fill out the width anymore either.
class MainDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<MainDrawerViewModel>(builder: (context, model, child) {
return Drawer(
child: Column(
children: [
DrawerHeader(
decoration: const BoxDecoration(color: ThemeColors.primaryDark),
child: Text(S.current.drawerTitle, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 30)),
),
SizedBox(
height: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: model.mainDrawerItems.length,
itemBuilder: (_, index) {
final drawerItem = model.mainDrawerItems[index];
return ListTile(
leading: drawerItem.icon,
title: Text(drawerItem.title, style: Theme.of(context).textTheme.headline6),
selected: model.currentScreen == drawerItem.screen,
selectedTileColor: ThemeColors.selectedDrawerItem,
onTap: () {
model.selectScreen(drawerItem.screen);
Navigator.pop(context);
},
);
}),
),
],
));
});
}
}
This feels like something that should be pretty easy... What am I missing here?
Use Expanded widget on listView instead of height: double.maxFinite,
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
double.maxFinite = 1.7976931348623157e+308; and it is equal to 1.7976931348623157 × 10^308 which is too big. and the overflow happens.
For header, you can wrap With SizedBox and provide width: double.maxFinite,. Also you can just use a container with decoration like
class MainDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: [
Container(
width: double.maxFinite,
height: 200, // based on your need
decoration: const BoxDecoration(color: Colors.amber),
padding: EdgeInsets.only(left: 16, top: 16),
child: Text(
"S.cu ",
style: TextStyle(
color: ui.Color.fromARGB(255, 203, 19, 19),
fontWeight: FontWeight.bold,
fontSize: 30),
),
),
Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: 3,
itemBuilder: (_, index) {
return ListTile(
leading: Icon(Icons.abc_outlined),
title: Text("drawerItem.title",
style: Theme.of(context).textTheme.headline6),
selected: true,
onTap: () {},
);
}),
),
],
));
}
}

A RenderFlex overflowed by 1443 pixels on the bottom

I am trying to make it scrollable...enter image description here For some reason its not not scrolling and i tried adding singleChildScrollview still not working.... Pls look at the picture to understand better... so i posted the full code so that you guys can help me better... This was the error i got "Consider applying a flex factor (e.g. using an Expanded widget) to force the children of the RenderFlex to fit within the available space instead of being sized to their natural size. This is considered an error condition because it indicates that there is content that cannot be seen. If the content is legitimately bigger than the available space, consider clipping it with a ClipRect widget before putting it in the flex, or using a scrollable container rather than a Flex, like a ListView."
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:memoryblog/helper/authenticate.dart';
import 'package:memoryblog/services/auth.dart';
import 'package:memoryblog/services/database.dart';
import 'package:memoryblog/views/create_blog.dart';
class MemoryRoom extends StatefulWidget {
#override
_MemoryRoomState createState() => _MemoryRoomState();
}
class _MemoryRoomState extends State<MemoryRoom> {
AuthMethod authMethod = new AuthMethod();
DatabaseMethods databaseMethod = new DatabaseMethods();
Stream blogsStream;
Widget BlogsList(){
return Container(
child: blogsStream != null ? Column(
children: <Widget>[
StreamBuilder(
stream: blogsStream,
builder: (context, snapshot){
if(snapshot.data == null) return CircularProgressIndicator();
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: snapshot.data.documents.length,
shrinkWrap: true,
itemBuilder: (context, index){
return BlogsTile(
authorName: snapshot.data.documents[index].data['memoryName'],
title: snapshot.data.documents[index].data['title'],
description: snapshot.data.documents[index].data['desc'],
imgUrl: snapshot.data.documents[index].data['imgUrl'],
);
}
);
},
)
],
) : Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
)
);
}
#override
void initState() {
// TODO: implement initState
databaseMethod.getData().then((result){
setState(() {
blogsStream = result;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
children: <Widget>[
Text(
"Memory"
),
Text(
"Blog",
style: TextStyle(
color: Colors.blue
),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
actions: <Widget>[
GestureDetector(
onTap: (){
authMethod.signOut();
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => Authenticate()
));
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.power_settings_new)),
)
],
),
body: BlogsList(),
floatingActionButton: Container(
padding: EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => CreateBlog()
));
},
child: Icon(Icons.add),
)
],
),
),
);
}
}
class BlogsTile extends StatelessWidget {
String imgUrl, title, description, authorName;
BlogsTile({#required this.imgUrl, #required this.title, #required this.description, #required this.authorName,});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16),
height: 170,
child: Stack(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(6),
child: CachedNetworkImage(
imageUrl: imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
)
),
Container(
height: 170,
decoration: BoxDecoration(
color: Colors.black45.withOpacity(0.3),
borderRadius: BorderRadius.circular(6)
),
),
Container(
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
SizedBox(height: 4,),
Text(
description,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
SizedBox(height: 4,),
Text(authorName)
],
),
)
],
),
);
}
}
Use ListView in place of the column. OR
Wrap Column with SingleChildScrollView
return Container(
child: blogsStream != null
? ListView(
children: <Widget>[
StreamBuilder(
stream: blogsStream,
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: snapshot.data.documents.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return BlogsTile(
authorName:
snapshot.data.documents[index].data['memoryName'],
title: snapshot.data.documents[index].data['title'],
description:
snapshot.data.documents[index].data['desc'],
imgUrl: snapshot.data.documents[index].data['imgUrl'],
);
});
},
)
],
)
: Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);

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())),
),
),
);
}

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,
);
}
}

Unable to get page scroll even adding the content inside a SingleChildScrollView or the ListView

I'm new to Flutter.
What I'm trying to achieve is a page that has a transparent AppBar with a widget behind it. That's how it looks now:
The problem is that, I can't make the page scroll when the content is bigger then the viewport height, even adding a SingleChildScrollView or adding the content inside a ListView, it just don't scrolls.
This is the page:
import 'package:cinemax_app/src/blocs/movie_bloc.dart';
import 'package:cinemax_app/src/components/movie/movie_header.dart';
import 'package:cinemax_app/src/models/movie.dart';
import 'package:flutter/material.dart';
import 'package:share/share.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
class MoviePage extends StatefulWidget {
final int movieId;
MoviePage({ this.movieId });
#override
_MoviePageState createState() => _MoviePageState();
}
class _MoviePageState extends State<MoviePage> {
#override
void initState() {
super.initState();
movieBloc.fetchMovie(widget.movieId);
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: movieBloc.movie,
builder: (context, snapshot) {
final _movie = snapshot.data as MovieModel;
return Scaffold(
body: SafeArea(
child: snapshot.hasData ?
Stack(
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
MovieHeader(movie: _movie),
Container(
padding: EdgeInsets.only(top: 45, bottom: 15, left: 15, right: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Sinopse:', style: Theme.of(context).textTheme.title),
HtmlWidget(
_movie.sinopsis,
bodyPadding: EdgeInsets.only(top: 15),
textStyle: TextStyle(color: Colors.grey),
)
],
),
)
]
),
AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
actions: <Widget>[
PopupMenuButton(
icon: Icon(Icons.more_vert),
itemBuilder: (BuildContext context) {
return <PopupMenuItem>[
PopupMenuItem(
child: Text('Partilhar'),
value: 'share'
),
PopupMenuItem(
child: Text('Comprar bilhete'),
value: 'share',
enabled: false,
),
];
},
onSelected: (selectedPopupValue) {
switch (selectedPopupValue) {
case 'share': {
final movieSlug = _movie.slug;
final movieAddress = 'https://cinemax.co.ao/movie/$movieSlug';
Share.share(movieAddress);
}
}
},
)
],
),
]
) :
Center(
child: CircularProgressIndicator(),
)
),
);
}
);
}
}
The MovieHeader widget:
import 'dart:ui' as prefix0;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cinemax_app/src/models/movie.dart';
import 'package:flutter/material.dart';
import 'movie_cover.dart';
class MovieHeader extends StatelessWidget {
const MovieHeader({Key key, #required MovieModel movie}) : _movie = movie, super(key: key);
final MovieModel _movie;
#override
Widget build(BuildContext context) {
return Container(
height: 250,
color: Colors.black,
child: Column(
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
overflow: Overflow.visible,
children: <Widget>[
new MovieBanner(movie: _movie),
Positioned(
bottom: -15.0,
left: 15.0,
right: 15.0,
child: Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
width: 125.0,
child: MovieCover(imageUrl: _movie.coverUrl)
),
Padding(padding: EdgeInsets.only(right: 15.0),),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text(
_movie.name,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
)
),
),
],
),
Padding(padding: EdgeInsets.only(bottom: 10.0),),
Text(
_movie.genresList,
style: TextStyle(
fontSize: 10.0,
color: Colors.white.withOpacity(0.6)
),
),
Padding(padding: EdgeInsets.only(bottom: 35.0),)
],
),
)
],
)
),
)
],
)
),
],
),
);
}
}
class MovieBanner extends StatelessWidget {
const MovieBanner({
Key key,
#required MovieModel movie,
}) : _movie = movie, super(key: key);
final MovieModel _movie;
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
Opacity(
child: CachedNetworkImage(
imageUrl: _movie.bannerUrl,
fit: BoxFit.cover,
),
opacity: 0.5,
),
Positioned(
child: ClipRect(
child: BackdropFilter(
child: Container(color: Colors.black.withOpacity(0)),
filter: prefix0.ImageFilter.blur(sigmaX: 5, sigmaY: 5),
),
),
)
],
);
}
}
Why is it happening? What I'm doing wrong?
An Example of Scrolling ListView using ListView Builder
class ScrollingList extends StatelessWidget{
List<String> snapshot= ["A","B","C","D","E","F","G"]
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder( //<----------- Using ListViewBuilder
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Card( //<--------- Using Card as per my requirement as a wrapper on List tile, you can use any other UI Element
child: ListTile( // populating list tile with tap functionality
title: Text(
'${snapshot.data[index]}',
maxLines: 1,
),
onTap: () {
print('TAPPED = ${snapshot.data[index]}') //<---- do anything on item clicked eg: open a new page or option etc.
}),
);
},
);
)
}
for any reference of single child scroll view here is a link