Is there any way to List the list views size in flutter? - flutter

I am new to flutter and trying to develop a version updation software. I need to show the version in a radio list. Is there any way to contain the list view in a container? Currently the list view is overflowing through the other widgets. I need to contain the list view between the text and the button. Is there any way to do it.The code the screenshot is given below
[![screenshot][1]][1]
Widget _createVersionRadioTiles(List<String> versions) {
var radioTiles = <Widget>[];
for (var version in versionList) {
var tile = Padding(
padding: const EdgeInsets.all(8.0),
child: RadioListTile<String>(
selected: selectedVersion == version,
tileColor: colorDarkGray,
// selectedTileColor: Colors.white,
value: version,
groupValue: selectedVersion,
onChanged: (String? value) {
setState(() {
selectedVersion = value!.toString();
});
},
title: Text(version),
),
);
radioTiles.add(tile);
}
return Column(
children: [
SizedBox(
height: 500,
width: 500,
child: ListView(children: radioTiles),
)
],
);
} ```
[1]: https://i.stack.imgur.com/qQxns.jpg

Wrap the RadioListTile with a Card widget. It will contain the ListTile in the container.

You can replace SizedBox with Container, and use clipBehavior: Clip.hardEdge to remove the overflows. see code below:
return Column(
children: [
Container(
height: 500,
width: 500,
clipBehavior: Clip.hardEdge,
child: ListView(children: radioTiles),
)
],
);

Related

Flutter - Update items in a ListView

I'm trying to change the order of widgets in a ListView as follows:
Widgets List
List<Widget> widgets = [const Text("Widget 1"), const Text("Widget 2")];
ListView
ListView(children: widgets),
Text("$widgets")
Function
() {
widgets.shuffle();
setState(() {
widgets = widgets;
});
}
This way the order of widgets is changed in the TEXT but not in the list as I intended.
Any idea?
First solution: Add Key to List ListView like this:
ListView(
key: UniqueKey(),// <--- add this
children: widgets,
),
also in your Function you don't need to pass widgets again:
() {
widgets.shuffle();
setState(() {});
}
Second solution: you can use SingleChildScrollView and Column like this:
Padding(
padding: const EdgeInsets.all(20.0),
child: SizedBox(
height: 50,
width: 100,
child: SingleChildScrollView(
child: Column(
children: widgets,
),
),
),
),

I want to show filter list in a container but it is opening as a new screen in flutter

This code is working, but I am not getting the output I want. I want to show this screen in a container but it's not working.
It's not opening in a container but instead directly opening as a different page.
I am using the flutter filter_list: ^1.0.2 plugin in this code.
I want to show this search bar with a list in a container on the same page.
List<SelectProjectData?> _selectProjectData = [];
openFilterDelegate() async {
await FilterListDelegate.show<SelectProjectData?>(
context: context,
list: _selectProjectData,
selectedListData: _selectedProjectData,
onItemSearch: (user, query) {
return user!.projectName!.toLowerCase().contains(query.toLowerCase());
},
tileLabel: (user) => user!.projectName,
emptySearchChild: const Center(child: Text('Data not found')),
// enableOnlySingleSelection: true,
searchFieldHint: 'Search Here..',
onApplyButtonClick: (list) {
setState(() {
_selectedProjectData = list!;
});
},
);
}
Try to call this in the column:- here you can find the code
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(20),
color: AppColor.WHITE,
child:
Column(
children: [
openFilterDelegate(),
],
),
);
The final result is this:-
Based on https://pub.dev/packages/filter_list, you want to use the FilterWidget instead of the FilterDelegate. FilterDelegate opens a new window every time. FilterWidget is a widget that you can put inside a container just like any other widget.
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(20),
color: AppColor.WHITE,
child:
Column(
children: [
FilterWidget(
<set up widget here>
),
],
),
);

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 to remove item at the top of List View in Flutter?

I have List View and I have inside each item in the list a button called "Delete item". When I press that button inside each item I want to delete only that item from the list.
But it does not delete item, it just display Toast message that I have specified.
How I can solve this?
This is the code:
Widget build(BuildContext context) {
listItems = buildVCsFromAPI(context);
return Container(
child: ListView.builder(
itemBuilder: (context, index) =>
_buildListItem(context, listItems[index], index),
itemCount: listItems.length,
physics: AlwaysScrollableScrollPhysics()),
);
}
Widget _buildListItem(
BuildContext context, _VerifiableCredentialListItem cert, int index) {
return GestureDetector(
child: AnimatedAlign(
curve: Curves.ease,
duration: Duration(milliseconds: 500),
heightFactor: selectedPosition == index ? factorMax : factorMin,
alignment: Alignment.topCenter,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(10)), //here
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
offset: Offset(0, -1),
blurRadius: 10.0)
]),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
HeadingRow(title: cert.fullTitle, appIcon: cert.appIcon),
displayListItem(index, selectedPosition, cert)
],
),
),
),
}
Column displayListItem(
int index, int selectedIndex, _VerifiableCredentialListItem cert) {
CredentialListGroupType groupType = cert.groupType;
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: UIConstants.s2,
),
buildAnotherWidget(),
SizedBox(
height: UIConstants.s3,
),
buildDeleteAndExportButtons(),
],
);
}
Column buildDeleteAndExportButtons() {
return Column(
children: [
Padding(
padding: EdgeInsets.symmetric(
vertical: UIConstants.s1, horizontal: UIConstants.s2),
child: Row(
children: [
Expanded(
flex: 1,
child: BlueButtonWithIcon(
text: 'Delete item',
icon: 'assets/icons/delete-icon.svg',
onPressed: () {
setState(() {
AppToaster.pop(ToasterType.info, "Delete");
listItems.removeAt(0);
});
},
),
),
SizedBox(width: UIConstants.s1),
Expanded(
flex: 1,
child: BlueButtonWithIcon(
text: 'Export',
icon: 'assets/icons/export.svg',
onPressed: null,
),
)
],
),
),
SizedBox(height: UIConstants.s1)
],
);
}
Calling setState doesn't mean that flutter would actually full repaint the screen it means that it will check your widget tree with the last rendered widget tree and it will paint only the differences and it first compares widgets type and then widget keys to find that there is a difference between the current widget and the previous one and because of this when you remove an item from your list of items flutter checks your returned widgets to the currently rendered widget it doesn't found any difference and it won't repaint the screen and continues showing the last render
So for you to tell the flutter that one of the items in the listView is changed you could assign a uniqueKey key for each list item widget note that for this topic your keys should be unique to the data of that widget otherwise you will face performance issues because if your widget key is changed without any change in the representation of that widget in next time that builds method is called which could happen frequently flutter compares widgets key with the previous widgets key which is rendered to the screen and exist on the render tree and it founds that the keys are different and it repaints that widget which is a redundant operation because your widgets UI and representation are the same
For example, assign a unique id base on the index or content of your data to each data model in the listItems and use that to create a ValueKey() for the widget that is represented by that data
here is a working example of the list which when you click on the list item first list item will be removed
class ListItemDataModel {
final String id;
final Color color;
ListItemDataModel(this.id, this.color);
}
class _MyHomePageState extends State<MyHomePage> {
List<ListItemDataModel> items = [];
#override
void initState() {
super.initState();
items = [
ListItemDataModel("A", Colors.red),
ListItemDataModel("B", Colors.amber),
ListItemDataModel("C", Colors.green),
ListItemDataModel("D", Colors.lightBlueAccent),
ListItemDataModel("E", Colors.pink),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
child: ListView.builder(
itemBuilder: (context, index) {
return GestureDetector(
key: ValueKey(items[index].id),
//Tap to Remove first item from list
onTap: () {
items.removeAt(0);
setState(() {});
},
child: Container(
height: 60,
color: items[index].color,
child: Center(
child: Text(
"This is a unique item with id = ${items[index].id}"),
),
),
);
},
itemCount: items.length,
),
),
);
}
}
So,
We don't have acces to the code above.. so.. where does listItems came from?
Maybe you are retrieving the value of listItems after the init state? if so it's normal that you are retrieving always the same result..
What you should do is the following:
get listItems value from params, global vars, databse ecc
display the list
when you delete a single item you should update the original list
on state updated now the list will be loaded with updated values
If you delete an item from a list but the list is then reloaded in its original form your updates will be lost

Flutter- Image picker package: show images one after another with delete action

In my Flutter pr project, I am using Image Picker plugin to select images from the android mobile gallery or capture images with the camera and show them one after another with a delete icon below each image. On tapping the RaisedButton for selecting images from the gallery, the method imageSelectorGallery() is called. There inside the setState() method , I add a SizedBox and a delete icon to the List namely images_captured. I expect the images_captured to be rendered inside the Column in SingleChildScrollView.
But after selecting an image from the gallery, nothing happens. I also want to tap on the delete icon and remove the image above it. But flutter has no data binding mechanism as I know to correlate the image with the delete button.
Code follows:
class PrescriptionScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new UserOptionsState();
}
}
class UserOptionsState extends State<PrescriptionScreen> {
//save the result of gallery fileUserOptions
File galleryFile;
//save the result of camera file
File cameraFile;
#override
Widget build(BuildContext context) {
var images_captured=List<Widget>();
//display image selected from gallery
imageSelectorGallery() async {
galleryFile = await ImagePicker.pickImage(
source: ImageSource.gallery,
// maxHeight: 50.0,
// maxWidth: 50.0,
);
print("You selected gallery image : " + galleryFile.path);
setState(() {
var sized_box_indiv= new SizedBox(
height: 200.0,
width: 300.0,
//child: new Card(child: new Text(''+galleryFile.toString())),
//child: new Image.file(galleryFile),
child: galleryFile == null
? new Text('Sorry nothing selected from gallery!!')
: new Image.file(galleryFile),
);
images_captured.add(sized_box_indiv);
var delete_button = IconButton(icon: Icon(Icons.delete), onPressed: () {});
images_captured.add(delete_button);
});
}
//display image selected from camera
imageSelectorCamera() async {
cameraFile = await ImagePicker.pickImage(
source: ImageSource.camera,
//maxHeight: 50.0,
//maxWidth: 50.0,
);
print("You selected camera image : " + cameraFile.path);
setState(() {});
}
return new SingleChildScrollView(
child:Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new RaisedButton(
child: new Text('Select Image from Gallery'),
onPressed: imageSelectorGallery,
),
new RaisedButton(
child: new Text('Select Image from Camera'),
onPressed: imageSelectorCamera,
),
Column(
children: images_captured
),
],
),
);
/* },
),
);*/
}
}
How to show the images selected from gallery one after another with a delete icon button below each of them?
How to remove the corresponding image on tapping the delete icon button?
I think if I can accomplish it for gallery, I can do it for camera capturing as well.
I used the answer by jJuice and the images after being selected showed overflow error. The screenshot is given below:
My code is:
class UserOptionsState extends State<PrescriptionScreen> {
//save the result of gallery fileUserOptions
File galleryFile;
//save the result of camera file
File cameraFile;
var images_captured=List<Widget>();
List<File> images = List<File>();
#override
Widget build(BuildContext context) {
//display image selected from gallery
imageSelectorGallery() async {
galleryFile = await ImagePicker.pickImage(
source: ImageSource.gallery,
// maxHeight: 50.0,
// maxWidth: 50.0,
);
images.add(galleryFile);
print("You selected gallery image : " + galleryFile.path);
setState(() {
});
}
//display image selected from camera
imageSelectorCamera() async {
cameraFile = await ImagePicker.pickImage(
source: ImageSource.camera,
//maxHeight: 50.0,
//maxWidth: 50.0,
);
print("You selected camera image : " + cameraFile.path);
setState(() {});
}
return new SingleChildScrollView(
child:Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new RaisedButton(
child: new Text('Select Image from Gallery'),
onPressed: imageSelectorGallery,
),
new RaisedButton(
child: new Text('Select Image from Camera'),
onPressed: imageSelectorCamera,
),
new Container(
// new Column(
// children: <Widget>[
height: 1200,
child:GridView.count(
crossAxisSpacing: 6,
mainAxisSpacing: 6,
crossAxisCount: 3,
children: List.generate(images.length, (index) {
return Column(
children: <Widget>[
Container(
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: ClipRRect(
child: Image.file(images[index], fit: BoxFit.cover),
borderRadius: BorderRadius.circular(10),
)
),
GestureDetector(
onTap: () {
setState(() {
images.removeAt(index);
});
},
child: Padding(
padding: const EdgeInsets.all(3.0),
child: Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.clear, color: Colors.black, size: 20),
),
),
),
]
);
}
),
),
// ]
)
/*displaySelectedFile(galleryFile),
displaySelectedFile(cameraFile)*/
],
),
);
}
Widget displaySelectedFile(File file) {
return new SizedBox(
height: 200.0,
width: 300.0,
//child: new Card(child: new Text(''+galleryFile.toString())),
//child: new Image.file(galleryFile),
child: file == null
? new Text('Sorry nothing selected!!')
: new Image.file(file),
);
}
}
Question 1: You first need to store the images picked by using ImagePicker (or MultiImagePicker plugin) in a collection. Here's an example on how to do that:
List<File> images = List<File>();
images.add(await ImagePicker.pickImage(source: ImageSource.gallery, imageQuality: 20););
When you want to show those images on the screen, you can use several different widgets, like ListView, GridView, Row, Column.
Here's an example where I use a GridView:
child: Container(
height: 1200,
child: GridView.count(
crossAxisSpacing: 6,
mainAxisSpacing: 6,
crossAxisCount: 3,
children: List.generate(images.length, (index) {
return Column(
children: <Widget>[
Container(
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
),
child: ClipRRect(
child: Image.file(images[index], fit: BoxFit.cover),
borderRadius: BorderRadius.circular(10),
)
),
GestureDetector(
onTap: () {
setState(() {
images.removeAt(index);
});
},
child: Padding(
padding: const EdgeInsets.all(3.0),
child: Align(
alignment: Alignment.bottomCenter,
child: Icon(Icons.clear, color: Colors.white, size: 20),
),
),
),
]
),
}
),
),
I think using a Stack widget works best in this case. A Stack can be used to show Widgets, layered on top of each other. So in this case, a widget showing the image, with a Icon widget on top of it that is the button for your delete action.
Question 2:
You could delete the image by calling the removeAt method available on collections like a List. See the code inside the onTap method of the GestureDetector. By calling setState the page gets rebuild once the image has been deleted.
EDIT
Sorry, I misread your question and see that you want to show a button below the image, instead of on top of it. A Column widget could be used for this purpose. I edited the code accordingly.