Flutter : Listview Builder Horizontal Inside Stack Widget - flutter

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

Related

Horizontal viewport was given unbounded height while using PageView.Builder

I'm working on simple quiz app with BLoC pattern. Tried to implement swipe feature for each quiz with PageView.Builder, here is my code
class _QuizScreenState extends State<QuizScreen> {
#override
void initState() {
context.read<QuizInfoBloc>().add(GetQuizStat("1"));
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: kSecondaryColor,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
actions: [],
),
body: Container(
decoration: BoxDecoration(color: kSecondaryColor),
width: double.infinity,
height: double.infinity,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 0),
child: Column(
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: kDefaultPadding / 2),
child: ProgressBar(),
),
Spacer(
flex: 1,
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: kDefaultPadding / 2),
child: BlocConsumer<QuizInfoBloc, QuizInfoState>(
listener: (context, state) {
// TODO: implement listener
},
builder: (context, state) {
if (state is QuizInfoLoaded) {
return PageView.builder(
itemCount: state.quiz.questions.length,
itemBuilder: (context, index) => QuestionCard(
question: state.quiz.questions[index]));
} else {
return Container(
height: 0,
width: 0,
);
}
},
),
),
Spacer(
flex: 4,
),
BottomButtons(),
SizedBox(
height: 20,
),
// AnswerExplanation(
// correctOrWrong: kGreenColor,
// ),
],
),
)),
),
);
}
}
I've tried with wrapping PageView.Builder with Expanded which was wrapped with Column. But still getting a different error
Padding(
padding:
const EdgeInsets.symmetric(horizontal: kDefaultPadding / 2),
child: BlocConsumer<QuizInfoBloc, QuizInfoState>(
listener: (context, state) {
// TODO: implement listener
},
builder: (context, state) {
if (state is QuizInfoLoaded) {
return Column(
children: [
Expanded(
child: PageView.builder(
itemCount: state.quiz.questions.length,
itemBuilder: (context, index) => QuestionCard(
question: state.quiz.questions[index])),
),
],
);
} else {
return Container(
height: 0,
width: 0,
);
}
},
),
),
RenderFlex children have non-zero flex but incoming height constraints
are unbounded.
QuestionCard
class _QuestionCardState extends State<QuestionCard> {
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(kDefaultPadding / 2),
child: Column(
children: [
Text(
this.widget.question.questionText,
style: Theme.of(context)
.textTheme
.headline5
?.copyWith(color: Colors.white, fontWeight: FontWeight.bold),
),
SizedBox(
height: 30,
),
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: this.widget.question.options.length,
itemBuilder: (BuildContext context, int index) {
return OptionUI(option: this.widget.question.options[index]);
})
],
),
);
}
}
Since you already have a kSecondaryColor as backgroundColor of your Scaffold, you don't need a Container as body of your Scaffold:
Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: kSecondaryColor,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
actions: [],
),
body: SafeArea(
// child: ...
),
)
A SafeArea widget is meant to be used on the top-level widget tree:
SafeArea(
Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: kSecondaryColor,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
actions: [],
),
body: Padding(
// child: ...
),
)
)
Wrap an Expanded into the Padding of your BlocConsumer:
Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPadding / 2),
child: ProgressBar(),
),
Spacer(flex: 1),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: kDefaultPadding / 2),
child: BlocConsumer<QuizInfoBloc, QuizInfoState>(
listener: (context, state) {
// TODO: implement listener
},
builder: (context, state) {
if (state is QuizInfoLoaded) {
return PageView.builder(
itemCount: state.quiz.questions.length,
itemBuilder: (context, index) =>
QuestionCard(question: state.quiz.questions[index]));
} else {
return Container(height: 0, width: 0);
}
},
),
),
),
Spacer(flex: 4),
BottomButtons(),
SizedBox(height: 20),
// AnswerExplanation(correctOrWrong: kGreenColor),
],
);
You didn't provide the ProgressBar, QuestionCard and BottomButtons widgets, so if the error persists you should check them, but I think these changes should suffice.

How To Make The Column Scrollable In Flutter Web?

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.

How to create expandable dynamic linear list and expandable grid list in a same widget?

I want to create 2 list type data
first linear and other grid type list
now requirement is that both data list height will be dynamic means it should be expand when , new object is added.
and sorting scrollable along with all 4 widgets(sort, list, sort, grid).
like below image:
i have tried but height is static ,
i have used expanded but not giving result as i'm expecting.
code:
Container(
padding: EdgeInsets.all(10),
child: Container(
child: Column(
children: [
sort(context),//sort widget
createForlderView(context), //dynamic list widget
sort(context), //sort widget
_createGridView()// dynamic grid list widget
],
),
),
);
Widget sort(BuildContext context){
return Container(
// color: Colors.red,
height: 25,
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Folder"),
Container(
// color:Colors.green,
width: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Sort"),
// SizedBox(width:5),
InkWell(onTap: () {}, child: Icon(Icons.sort))
],
),
),
],
),
);
}
// list view:
Widget createForlderView(BuildContext context) {
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
return Expanded(
child: Container(
height: _height / 1.2,
child: ListView.builder(
// padding: ,
itemCount: directoryItems.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Container(
height: 30,
width: 30,
child: Icon(Icons.folder, color: Colors.brown),
),
title: Text(directoryItems[index]),
subtitle: Text("15 items"),
trailing:
IconButton(icon: Icon(Icons.more_vert), onPressed: () {}),
));
}),
),
);
}
// grid view:
Widget _createGridView() {
var mSize = MediaQuery.of(context).size;
/*24 is for notification bar on Android*/
final double itemHeight = (mSize.height - kToolbarHeight) / 2;
final double itemWidth = mSize.width / 2;
int gridItemCount =
Provider.of<DocumentProvider>(context).allDocuments.length;
return Expanded(
child: Container(
height: 100,
child: GridView.count(
key: animatedListKey,
scrollDirection: Axis.vertical, //default
reverse: false,
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0,
childAspectRatio: (itemWidth / itemHeight),
children: List.generate(gridItemCount, (index) {
return Center(
child: SelectCard(
index: index,
itemHeight: itemHeight,
itemWidth: itemWidth,
deletefun: () {
Navigator.pop(context);
DeleteDialog(
index: index,
dateTime:
Provider.of<DocumentProvider>(context, listen: false)
.allDocuments[index]
.dateTime);
},
),
);
}),
),
),
);
}
output screen:
I have found my solution,
used CustomScrollView along with it's slivers: SliverToBoxAdapter (for single widget),SliverFixedExtentList (for linear list) , and SliverGrid (for Grid list).
import 'package:flutter/material.dart';
class ExpandableList extends StatefulWidget {
final List<FolderModel> listData;
final List<FilesModel> gridListData;
const ExpandableList({Key key, this.listData, this.gridListData}) : super(key: key);
#override
_ExpandableListState createState() => _ExpandableListState();
}
class _ExpandableListState extends State<ExpandableList> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
buildAppBar(),
sorting(title: "folders", tralingTitle: "sort", onTap: (){}),
expandableListBuilder(),
sorting(title: "files", tralingTitle: "sort",onTap: (){}),
expandableGridList(),
],
)
);
}
buildAppBar(){
return SliverAppBar(
title: Text("Multi Expandable list example"),
centerTitle: true,
pinned: true,
);
}
expandableListBuilder(){
return SliverFixedExtentList(
itemExtent: 75.0,
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
child: ListTile(
leading: Container(
height: 30,
width: 30,
child: Icon(Icons.folder, color: Colors.brown),
),
title: Text(widget.listData[index].title),
subtitle: Text(widget.listData[index].subtitle),
trailing:
IconButton(icon: Icon(Icons.more_vert), onPressed: () {}),
));
},
childCount: widget.listData.length
),
);
}
expandableGridList(){
return SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200.0,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Card(
elevation: 8,
child: Container(
alignment: Alignment.center,
height: 100,
width: 100,
child: Text("${widget.gridListData[index].title}${(index+1).toString()}"),
),
);
},
childCount: widget.gridListData.length,
),
);
}
sorting({String title,String tralingTitle, void Function() onTap}){
return SliverToBoxAdapter(
child: Container(
padding: const EdgeInsets.all(10),
height: 50,
width: MediaQuery.of(context).size.width,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title),
Container(
// color:Colors.green,
width: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(tralingTitle),
// SizedBox(width:5),
InkWell(
onTap:onTap,
child: Icon(Icons.sort))
],
),
),
],
),
),
);
}
}
result:

implementing nested ListView inside SingleChildScrollView

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

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