Fluter- 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 android mobile gallery or capture images with camera and show them one after another with a delete icon below each image. On tapping the RaisedButton
for selecting images from the gallery, 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
),
],
),
);
/* },
),
);*/
}
}
Q1: How to show the images selected from gallery one after another with a delete
icon button below each of them ?
Q2: 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....
EDIT:
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.