Vertical scrolling with horizontal scrolling lists render errors - flutter

Having difficulty with a Flutter layout which includes an appBar() at the top, a BottomNavigationWidget() at the bottom and content in the middle that is vertically scrollable but has horizontal list views as well. The problem is I continue to run into viewport errors that vary in their specificity, no matter what I attempt to correct or modify related to the SingleChildScrollView() that sits beneath the appBar().
Each horizontal row is built from a future that returns a list of images that comes from ContentList. Since I need to be able to make multiple requests for different images in each horizontal row, I call buildCategory("title", 0), buildCategory("new title", 1), buildCategory("another title", 2)and so on, as to pull down different images and display them with a unique title as illustrated in the image below.
I've constructed that layout like so below however you can't scroll vertically, only horizontally on each included buildCategory method despite being wrapped in a SingleChildScrollView and contained within a Column. If I deviate from this I get layout exceptions thrown.
I've included the full code I'm working with to better share/show.
Future<List<ContentDetails>> getContent(http.Client client, int filter) async {
var response = await client.get(
Uri.parse(baseUrl + '/imageendpoint/$filter'));
if (response.statusCode == 200) {
compute(parseContentDetails, response.body);
}
}
List<ContentDetails> parseContentDetails(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed
.map<ContentDetails>((json) => ContentDetails.fromJson(json))
.toList();
}
class ContentList extends StatefulWidget {
const ContentList({Key? key, required this.photos}) : super(key: key);
final List<ContentDetails> photos;
#override
State<ContentList> createState() => _ContentListState();
}
class _ContentListState extends State<ContentList> {
#override
Widget build(BuildContext context) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: widget.photos.length,
itemBuilder: (context, index) {
return Stack(
alignment: Alignment.topCenter,
children: <Widget>[
InkWell(
onTap: () {},
child: Container(
height: 150.0,
width: 150.0,
child: Container(
image: DecorationImage(
fit: BoxFit.cover,
alignment: FractionalOffset.center,
image: widget.photos[index].image,
),
),
child: Container(
child: Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Text(widget.photos[index].name)),
),
),
),
),
),
],
);
},
);
}
}
Widget appBar() {
return AppBar(
title: const Text("Welcome"),
centerTitle: true,
backgroundColor: Colors.transparent
);
}
Widget horizontalContent(int filter) {
return FutureBuilder<List<ItemDetails>>(
future: getContent(http.Client(), filter),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('Error.'),
);
} else if (snapshot.hasData) {
return ContentList(photos: snapshot.data!);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
Widget buildCategory(String title, int category) {
return Flexible(
child: ListView(
shrinkWrap: true,
children: [
Padding(
padding: const EdgeInsets.all(5.0),
child:
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
TitleWidget(
titleText: title,
titleAlign: TextAlign.right),
SmallButton(
buttonText: "Details",
onPressed: () => {},
)
]),
),
SizedBox(height: 200, child: horizontalContent(filter))
],
),
);
}
class _MainPageState extends State<MainPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
bottomNavigationBar: BottomNavigationWidget(),
body: Stack(
children: <Widget>[
Container(
width: double.infinity,
height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromRGBO(0, 85, 85, 85),
Color.fromRGBO(0, 66, 66, 66),
Color.fromRGBO(0, 0, 0, 0),
],
stops: [0.0, 0.3],
),
),
child:
Image.asset("images/background.png", fit: BoxFit.cover)),
appBar(),
SingleChildScrollView(
child: Column(mainAxisSize: MainAxisSize.min, children: [
buildCategory("title", 0),
buildCategory("title", 1),
buildCategory("title", 2),
buildCategory("title", 3),
buildCategory("title", 4),
buildCategory("title", 5),
buildCategory("title", 6),
])),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[BottomNavigationWidget()],
),
],
),
);
}
}

On your Scaffold use appBar and
AppBar appBar() {
return AppBar(
title: const Text("Welcome"),
centerTitle: true,
backgroundColor: Colors.transparent);
}
return Scaffold(
appBar: appBar(),
// bottomNavigationBar: ,
body: ListView.builder( // top level listView
itemCount: 44,
itemBuilder: (context, index) {
return Container(
height: 200, // must provide based on your preference
child: Column(
children: [
Row(
children: [
Text("header $index"),
],
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 33,
itemBuilder: (context, index) => Container(
width: 200,
height: 100,
child: Text("hrIem"),
),
),
),
],
),
);
},
),
);

Try this
Scaffold(
extendBodyBehindAppBar: true,
appBar: appBar(),
bottomNavigationBar: BottomNavigationWidget(),
body: ListView(
children: [
SizedBox(
height: 300, // give your height
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
mainAxisSize: MainAxisSize.min, children: [
buildCategory("title", 0),
buildCategory("title", 1),
buildCategory("title", 2),
buildCategory("title", 3),
buildCategory("title", 4),
buildCategory("title", 5),
buildCategory("title", 6),
]
)
),
),
SizedBox(
height: 300, // give your height
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Column(
mainAxisSize: MainAxisSize.min, children: [
buildCategory("title", 0),
buildCategory("title", 1),
buildCategory("title", 2),
buildCategory("title", 3),
buildCategory("title", 4),
buildCategory("title", 5),
buildCategory("title", 6),
]
)
),
)
]
),
)

Related

it's possible to make listview in expand and fill parent without overflow?

it's possible to make listview in expand and fill the container without overflow the container, and shrink when listview is short of content without declare manual min or max height?
Code
Flexible(
fit: FlexFit.loose,
child: Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 10),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(kBoxRadius),
boxShadow: [kBoxShadow]),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
DText(
"Aug 2021",
size: 12,
weight: FontWeight.bold,
),
SizedBox(height: 10),
Row(
children: dates,
),
SizedBox(height: 15),
Container(
height: 1,
color: Color(0xFFE7E7E7),
),
Container(
constraints:
BoxConstraints(minHeight: 0, maxHeight: 600),
child: ListView.separated(
shrinkWrap: true,
itemBuilder: (context, index) {
return DText("Asd");
},
separatorBuilder: (_, __) {
return SizedBox(height: 10);
},
itemCount: 20,
),
)
],
),
),
)
Expectation
when the content is big
because i set manually max height.
Yes, it is possible using shrinkWrap: true. The code will be something like below,
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
color: Colors.red,
child: ListView(
shrinkWrap: true,
children: <Widget>[
ListTile(title: Text('Apple')),
ListTile(title: Text('Orange')),
ListTile(title: Text('Banana')),
],
),
),
),
),
);
}
}

Horizontal viewport was given unbounded height - Flutter

I'm a newbie in App development and encountering an error while rendering the Horizontal Card scroll.
howItWorks.dart
class HowItWorksCards extends StatefulWidget {
HowItWorksCards();
#override
_HowItWorksCardsState createState() => _HowItWorksCardsState();
}
class _HowItWorksCardsState extends State<HowItWorksCards> {
int _currentPage = 0;
PageController _pageController = PageController(viewportFraction: 0.8, keepPage: true);
List<Widget> _pages = [
SliderPage(
index: 1,
title: "Title1",
info:"Summary",
image: "assets/images/howItWorks/1.png"),
SliderPage(
index: 1,
title: "Title1",
info:"Summary",
image: "assets/images/howItWorks/1.png"),
SliderPage(
index: 1,
title: "Title1",
info:"Summary",
image: "assets/images/howItWorks/1.png"),
];
_onchanged(int index) {
setState(() {
_currentPage = index;
});
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
flex: 5,
child: PageView.builder( // this throws the exception.
controller: _pageController,
// physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: _pages.length,
onPageChanged: _onchanged,
itemBuilder: (context, int index) {
return _pages[index];
},
),
),
Flexible( // this works absolutely fine when the above Flexible widget is commented.
flex: 4,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: List<Widget>.generate(
_pages.length,
(int index) {
return AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 5,
width: (index == _currentPage) ? 30 : 10,
margin: EdgeInsets.symmetric(horizontal: 5, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: (index == _currentPage)
? AppTheme.globalTheme.primaryColor
: AppTheme.globalTheme.primaryColor
.withOpacity(0.5)));
},
)),
),
],
);
}
}
slider.dart
class SliderPage extends StatelessWidget {
final String image;
final int index;
final String title;
final String info;
SliderPage(
{#required this.image,
#required this.info,
#required this.title,
#required this.index});
#override
Widget build(BuildContext context) {
return Card(
elevation: 20,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(5.0),
height: 175,
child: Image.asset(
image,
fit: BoxFit.fitHeight,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(this.title,
style: getFontStyle(
bold: true,
color: Color(0xFF3C3C43),
fontSize: 18,
fontStyle: FontStyles.SFProDisplay),
textAlign: TextAlign.center),
),
],
),
),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5),
child: Text(
this.info,
style: getFontStyle(
color: Color(0xFF3C3C43),
fontSize: 16,
fontStyle: FontStyles.SFProDisplay),
textAlign: TextAlign.center,
),
),
]),
);
}
}
main.dart
void main() => runApp(MaterialApp(home: AmazonOrdersInvoiceOnboarding()));
class AmazonOrdersInvoiceOnboarding extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: GoBackAppBar(
customBackGroundColor: Color(0x1affb500),
title: "",
),
body: ListView(
shrinkWrap: true,
children: [
HowItWorksCards(),
],
),
);
}
}
I'm getting some exceptions.
Horizontal viewport was given unbounded height. - Have already used Flexible. Not sure why I'm still getting this exception.
RenderBox was not laid out: RenderViewport#c29be NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I found a lot of related questions on SO, but to no avail.
This error happen when we use infinite sized widget inside one-another,
here you are using Column inside ListView, both take infinite height, if you wrap Column fixed sized widget it will solve the problem,
And I strongly suggest you to watch this video by flutter
https://www.youtube.com/watch?v=jckqXR5CrPI
on howItWorks.dart
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
flex: 5,
child: Container(
height: 250,
child: PageView.builder(
// this throws the exception.
controller: _pageController,
// physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: _pages.length,
onPageChanged: _onchanged,
itemBuilder: (context, int index) {
return _pages[index];
},
),
),
),
Flexible(
// this works absolutely fine when the above Flexible widget is commented.
flex: 4,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: List<Widget>.generate(
_pages.length,
(int index) {
return AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 5,
width: (index == _currentPage) ? 30 : 10,
margin: EdgeInsets.symmetric(horizontal: 5, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.amber)
// (index == _currentPage)
// ? AppTheme.globalTheme.primaryColor
// : AppTheme.globalTheme.primaryColor
// .withOpacity(0.5))
);
},
)),
),
],
);
}

Vertical ListView inside ScrollView flutter

My UI use case is similar to an Instagram user profile.
I have multiple widget on top and an infinite ListView.builder bellow with item.
I would like to scroll everything like within a ScrollView but the scrollview can not contain an infinite list.
How can I handle this situation in Flutter ?
Using CustomScrollView is the Solution
Here i have done Basic Implementation for you :
class MainBody extends StatefulWidget {
MainBody({Key key}) : super(key: key);
#override
_MainBodyState createState() => _MainBodyState();
}
class _MainBodyState extends State<MainBody> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Container(
height: 100,
width: 100,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.green),
child: Center(child: Text("ProfileImage")),
),
flex: 1,
),
Expanded(flex: 2, child: Text("Profile Statistics"))
],
),
Text("Bio"),
Text("Some Buttons"),
Text("Story Highlights"),
])),
),
SliverToBoxAdapter(
child: Container(
height: 150,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
margin: const EdgeInsets.all(10),
height: 100,
width: 100,
decoration: BoxDecoration(
shape: BoxShape.circle, color: Colors.red),
child: Center(child: Text((index + 1).toString())),
);
})),
),
SliverAppBar(
centerTitle: false,
pinned: true,
flexibleSpace: DefaultTabController(
initialIndex: 0,
length: 2,
child: TabBar(tabs: [
Center(child: Text("Icon1")),
Center(child: Text("Icon2")),
]),
),
),
SliverPadding(
padding: const EdgeInsets.all(8),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => Container(
height: 30,
child: Center(child: Text("Hey" + index.toString()))),
childCount: 20)),
)
],
),
);
}
}
Futher Enhancements can be done

render slivergrid using bloc in flutter

Here is the case :-
i have a Bloc named XYZBloc which loads data from network. i need to render these lists into sliverGrid.
the same list goes pretty well with sliverList.
Store.dart
#override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => _xyzBloc,
child: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
width: MediaQuery.of(context).copyWith().size.width,
height: MediaQuery.of(context).copyWith().size.height,
child: BlocBuilder<XyzBloc, XyzState>(
bloc: _xyzBloc,
builder: (context, state) {
if (state is XYZLoadingState) {
return buildLoading();
} else if (state is XYZErrorState) {
return buildErrorUi(state.message);
} else if (state is XYZLoadedState) {
return _buildPageView(state.lists, context);
} else {
return Container();
}
}),
),
),
);
}
_buildPageView(List<XYZModel> lists, BuildContext context) {
return SliverGrid(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
delegate: SliverChildBuilderDelegate((BuildContext context, int index) {
return Container(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
color: Colors.grey, height: 130.0, width: double.infinity),
Text(lists[index].name)
],
),
);
}, childCount: lists.length),
);
}
code to load sliverGrid data :-
Home.dart
#override
Widget build(BuildContext context) {
double cardWidth = MediaQuery.of(context).size.width / 3.3;
double cardHeight = MediaQuery.of(context).size.height / 3.6;
return Container(
color: AppTheme.nearlyWhite,
child: Scaffold(
backgroundColor: Colors.transparent,
body: Column(
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).padding.top,
),
getAppBarUI(),
Expanded(
child: CustomScrollView(
slivers: <Widget>[
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: EdgeInsets.all(15),
child: Container(
width: MediaQuery.of(context).size.width,
height: 150,
child: BannerItems(),
),
),
])),
SliverList(
delegate: SliverChildListDelegate(
[
Padding(
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
child: Container(
decoration: BoxDecoration(color: Colors.transparent),
height: 100,
child: Category(),
),
),
],
),
),
Stores(),
],
)),
],
),
),
);
}
i have tried all possible way to debug but my noob sense couldn't help me to understand how this sliverGrid works with network data.
any suggestion, reference will be highly appreciated.

ListView causes whitescreen below Appbar

I have a function that returns a Widget into my builder.
I want it to return a ListView, but everything below the Appbar just gets white with this piece of code in my return:
#override
Widget details(BuildContext context) {
var cell = (Widget widget) => Padding(
padding: EdgeInsets.all(5),
child: widget,
);
var locale = Localizations.localeOf(context);
return ListView(
children: <Widget>[
ListTile(title: Text("Test")),
],
);
}
The calling builder has this as body:
return Container(
//padding: EdgeInsets.all(32),
child: Column(
children: [
Container(
color: Color.fromRGBO(49, 161, 181, 0.4),
child:
Hero(
tag: collectible.heroTag,
child: Container(
width: double.infinity,
height: 250,
child: FadeInImage(
image: collectible.detailImage,
placeholder: collectible.icon,
fadeInDuration: Duration(milliseconds: 100),
fadeOutDuration: Duration(milliseconds: 100),
fadeInCurve: Curves.linear,
fadeOutCurve: Curves.linear,
// errorBuilder: (context, obj, satckTrace) =>
// Image.asset('images/bildfehlt.png'),
),
alignment: Alignment.center,
),
),
),
CheckboxListTile(
title: Text("Got it"),
controlAffinity: ListTileControlAffinity.leading,
value: collectible.isObtained(settings),
onChanged: (value) {
collectible.setObtained(settings, value);
},
),
collectible.details(context), // <-------- function
],
),
);
Did I implement sth wrong?
Any other widget, Container or Column for Example just work fine.
Error-Log:
https://pastebin.com/geSBXcB6