Flutter GridView.builder is Generating Unwanted Extra Space - flutter

I am trying to display a row of buttons. Since the number of buttons depends on the number of elements in a List, I have to use GridView.builder to dynamically create the right amount of buttons. Unfortunately it seems that GridView.builder is taking up alot of unnecessary space. Anyone know what is wrong here?
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Dice buttons
Flexible(
child: GridView.builder(
itemCount: dices.length,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: dices.length,
),
itemBuilder: (BuildContext context, int index) {
return new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ButtonTheme(
minWidth: 50.0,
height: 50.0,
child: RaisedButton(
child: Text(
dices[index].toString(),
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
color: usedDices[index] || !expectNum
? Colors.grey
: Colors.black,
onPressed: () {
if (!usedDices[index] && expectNum) {
setState(() {
numUsed[turn] = dices[index].toString();
numUsedIndex[turn] = index;
});
expectNum = false;
usedDices[index] = true;
}
},
),
),
]);
})),
Link to Pic: https://drive.google.com/file/d/1_Jr4rz9GJ-D8-Xjxs2w8Sn8lOdnBBqTc/view?usp=sharing
As you can see are lots of unnecessary space here and it seems to be the reuslt of GridView.builder

That space is the result of Flexible, which fills the available space. You will see that if you replace it with a Container and give it a height, it won't produce that much space below.

Just had this problem, top SliverPadding is set to 20.0 by default. Looking at docs I see:
/// By default, [ListView] will automatically pad the list's scrollable
/// extremities to avoid partial obstructions indicated by [MediaQuery]'s
/// padding. To avoid this behavior, override with a zero [padding] property.
So,
GridView.builder(
// shrinkWrap: true,
padding: EdgeInsets.zero,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisSpacing: 1,
mainAxisSpacing: 1,
crossAxisCount: 3,
),
itemBuilder: (context, index) {
return Container(
color: Colors.black,
);
},
itemCount: 10,
),
or
If you put a widget before the ListView, you should wrap the ListView with a
MediaQuery.removePadding widget (with removeTop: true)

Related

Fill the available space in Listtile

I am new to the flutter and trying to fill the empty space in the listtile. I tried to use dense and visualDensity but with that, I am not getting the required result. Any support and suggestions will be appreciated.
here is my code and output:
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(
height: isLargeScreen ? 300 : 200,
child: ListView.builder(
physics: const ScrollPhysics(),
shrinkWrap: true,
itemCount: tags.length,
itemBuilder: (context, index) {
return CheckboxListTile(
value: tempSelectedTags.contains(tags[index].id),
onChanged: (e) {
setState(() {
if (tempSelectedTags.contains(tags[index].id)) {
tempSelectedTags.remove(tags[index].id);
} else {
tempSelectedTags.add(tags[index].id);
}
});
},
title: Text(
tags[index].name,
style: !tempSelectedTags.contains(tags[index].id)
? theme.textTheme.labelMedium?.copyWith(
color: ThemeConfig.colorTertiary)
: theme.textTheme.titleSmall?.copyWith(
color: ThemeConfig.colorTertiary),
),
);
}),
),
const Spacer(),
Padding(
padding: const EdgeInsets.only(bottom:sdPaddingMedium),
child: SdPrimaryButton(
title: appLocalizations.btnApply,
onPressed: () {
viewModel.setTags(tempSelectedTags);
Navigator.pop(context);
},
),
),
],
)
Output can be seen here
There are two important things that determine the vertical layout in your column.
The whole box has a fixed size
SizedBox(
height: isLargeScreen ? 300 : 200,
There is a flexible space between the checkbox options and the bottom-right button
const Spacer(),
So if you want to remove the space, you can either
reduce the overall box size or
replace the const Spacer with a constant spacing like
SizedBox(height: 50) and also remove the SizedBox, so that the whole box will be content-sized

How can I prevent options view of the RawAutocomplete widget from overflowing on screen in Flutter?

I'm currently using a custom widget similar to this chips_input library. However, I don't want to give the options view (the popup list) a static maximum height. What I want to achieve is to dynamically set a maximum height of screen height - popup y offset. In this way, bottom of the options view will be at the bottom of the screen and all of the content inside the options view will be visible through scrolling. Is there any that I can access the textfield's or options view's offset to calculate the height?
My autocomplete widget looks similar to this:
RawAutocomplete<T>(
...
optionsViewBuilder: Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: textFieldWidth,
child: Material(
elevation: 16,
child: ListView.builder(
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final T option = options.elementAt(index);
return suggestionBuilder(context, option);
},
),
),
),
),
);
You can do this by putting a height on your SizedBox that uses MediaQuery to get the screen height:
popupOffset = 20;
RawAutocomplete<T>(
...
optionsViewBuilder: Align(
alignment: Alignment.topLeft,
child: SizedBox(
width: textFieldWidth,
height: MediaQuery.of(context).size.height - popupOffset,
child: Material(
elevation: 16,
child: ListView.builder(
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final T option = options.elementAt(index);
return suggestionBuilder(context, option);
},
),
),
),
),
);

how to align listview items top left?

i am trying to align list view items at the top left, but it aligns them in the center. I tried this with another widget, it works fine, but with the listview, it doesn't.
here is my code
Container(
height: height * 30,
// color: Colors.grey[400],
alignment: Alignment.topLeft,
child: ListView.builder(
itemBuilder: (context, i) => ReviewItem(
review: book.reviews[i]['review'],
date: book.reviews[i]['date'],
),
itemCount: book.reviews.length,
),
),
this is the review item
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
timeago.format(DateTime.parse(date)),
style: Theme.of(context).textTheme.headline4.copyWith(
fontSize: width * kFont12Ratio, color: Colors.grey[500]),
),
SizedBox(height: height * 0.5),
Text(review),
Divider(),
],
);
Thanks in advance
By default, ListView will automatically pad the list's scrollable extremities to avoid partial obstructions indicated by MediaQuery's padding. In other words, if you put a widget before the ListView, you should wrap the ListView with a MediaQuery.removePadding widget (with removeTop: true). Like so:
MediaQuery.removePadding(
context: context,
removeTop: true,
child: ListView.builder(...),
);
I achieved that by adding padding inside the listview builder
padding: EdgeInsets.only(top: 0),
You can use padding instead
Or use Stack with Position (top:0,left:0)
Or use Align( )

How to make a container 'lighten' on hold / on tap in Flutter?

I am trying to create an app with a scroll view and the objects are clickable like the google news app. Can anyone answer how to animate the container to have a white glow on holding the tile?
Here is the list view builder I have for the app
Container(
padding: EdgeInsets.only(top: 16),
child: ListView.builder(
physics: ClampingScrollPhysics(),
itemCount: article.length,
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemBuilder: (context, index) {
return news_tile(
imageurl: article[index].urlToimage,
news_title: article[index].title,
news_desc: article[index].description,
web_url: article[index].url
);
}),
)
and this is the contents of the tile which the list view builder calls
class news_tile extends StatelessWidget {
String imageurl, news_title, news_desc,web_url;
news_tile({this.imageurl, this.news_title, this.news_desc,this.web_url});
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(
builder: (context) => article_view(
web_url: web_url,
)
));
},
child: Container(
margin: EdgeInsets.only(bottom: 16),
child: Column(
children: <Widget>[
ClipRRect(borderRadius: BorderRadius.circular(6), child: Image.network(imageurl)),
SizedBox(
height: 8,
),
Text(news_title, style: TextStyle(fontSize: 17,fontWeight: FontWeight.w600)),
SizedBox(
height: 8,
),
Text(news_desc, style: TextStyle(color: Colors.black54))
],
),
),
);
}
}
You could go with the InkWell Widget. It provides a tapping/holding color effect similar to that. Have a look at the official docs here:
https://api.flutter.dev/flutter/material/InkWell-class.html
Note that you need a Material Widget as an ancestor of your InkWell, but the docs explain that more.
Hope it works for you!
Edit: Sorry, since you are working with a Container, Ink is also important for you:
https://api.flutter.dev/flutter/material/Ink-class.html
Check the docs section "The ink splashes aren't visible!" for why that is.

ListView.builder show anything

AlertCardWidget is a widget that i wrote. I return it in itemBuilder but nothing shown. Here is my code:
Flexible(
child: Padding(
child: SingleChildScrollView(
child: ListView.builder(
itemCount: state.data.length,
itemBuilder: (BuildContext context, int index) {
state.data["datas"].map<Widget>((f) {
return AlertCardWidget(
positionId: "${f["8020074"]}",
shipowner: "${f["8020076"]}",
customer: "${f["8020170"]}",
salesRepresenter: "${f["8020176"]}",
operationRepresenter: "${f["8020177"]}",
textContentFontColor:
AppTheme(Theme.of(context).brightness)
.cardFontBackgroundColor,
textfont: Colors.redAccent,
);
}).toList();
},
),
),
),
),
No error to show.
I have items that why I use ListView. The problom of using Listview instead ListView.builder is taking "Vertical viewport was given unbounded height error". The problem has solved when writing Listview like child of Expanded widget. Here is my code:
Expanded(
child: Padding(
padding: const EdgeInsets.all(4.0),
child: ListView(
children: state.data["datas"].map<Widget>((f) => AlertCardWidget(positionId: "${f["8020074"]}",
shipowner: "${f["8020076"]}",
customer: "${f["8020170"]}",
salesRepresenter: "${f["8020176"]}",
operationRepresenter: "${f["8020177"]}",
textContentFontColor: AppTheme(Theme.of(context).brightness).cardFontBackgroundColor,
textfont: Colors.redAccent,)).toList(),
),
),
),
Maybe a silly question, but why are you mapping a list into a ListView.builder?
Have you tried using the index for each iteration instead?
Because what I understand from that code is that every ["datas"] item you've got will generate the whole list for as many times as state.data.length has.
Maybe try this out:
Flexible(
child: Padding(
child: SingleChildScrollView(
child: ListView.builder(
itemCount: state.data.length,
itemBuilder: (BuildContext context, int index) {
return AlertCardWidget(
positionId: state.data[index]["datas"]["8020074"],
shipowner: state.data[index]["datas"]["8020076"],
customer: state.data[index]["datas"]["8020170"],
salesRepresenter: state.data[index]["datas"]["8020176"],
operationRepresenter: state.data[index]["datas"]["8020177"],
textContentFontColor:
AppTheme(Theme.of(context).brightness)
.cardFontBackgroundColor,
textfont: Colors.redAccent,
);
},
),
),
),
),
If that doesn't work, would you mind showing us which data are you trying to retrieve?
Your itemBuilder function does not return a value.
Edit: It should return a single Widget for every entry in your list.
Something like this should work.
Also, Padding Widget is missing the padding property.
Flexible(
child: Padding(
child: SingleChildScrollView(
child: ListView.builder(
itemCount: state.data.length,
itemBuilder: (BuildContext context, int index) {
final f = state.data[index];
return AlertCardWidget(
positionId: "${f["8020074"]}",
shipowner: "${f["8020076"]}",
customer: "${f["8020170"]}",
salesRepresenter: "${f["8020176"]}",
operationRepresenter: "${f["8020177"]}",
textContentFontColor:
AppTheme(Theme.of(context).brightness)
.cardFontBackgroundColor,
textfont: Colors.redAccent,
);
},
),
),
),
),