Want to add multiple images by extracting one method - flutter

I wanted to add 3 circle image picker avatar and wanted to upload 3 different pictures in them but unfortunately not able to do that. I tried to do this by extracting the method and passing the image to the single extracted build method and in result the chosen one image is applied to all three avatars. Kindly help me get through it.
Below are the functions for picking image from gallery and camera :
File _image;
final Picker = ImagePicker();
_imgFromCamera() async {
final image = await Picker.pickImage(
source: ImageSource.camera, imageQuality: 50
);
setState(() {
_image = File(image.path);
});
}
_imgFromGallery() async {
final image = await Picker.pickImage(
source: ImageSource.gallery, imageQuality: 50
);
setState(() {
_image = File(image.path);
});
}
Next is function for bottom sheet for picking the image either from gallery or camera:
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Photo Library'),
onTap: () {
_imgFromGallery();
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
_imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
}
);
}
And here is the extracted method that I want to use for once for all three images:
GestureDetector buildGestureDetector(BuildContext context) {
return GestureDetector(
onTap: () {
_showPicker(context);
},
child: CircleAvatar(
radius: 53,
backgroundColor: Colors.black,
child: _image != null
? ClipRRect(
borderRadius: BorderRadius.circular(50),
child: Image.file(
_image,
width: 100,
height: 100,
fit: BoxFit.fitHeight,
),
)
: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(50)),
width: 100,
height: 100,
child: Icon(
Icons.camera_alt,
color: Colors.grey[800],
),
),
),
);
}
}
And here is that extracted method is called inside widget :
Row(
children: [
Expanded(
child: buildGestureDetector(context),
),
],
),
Kindly help me with applying 3 different pictures using this one extracted method and all the functions used once so that I don't need to go through all this process for all three pictures again and again.

The easiest way to handle this is of course passing "which avatar" info down to _imgFromCamera or _imgFromGallery .
For example, if your 3 images have their own identities like 'A', 'B' and 'C',
onTap: () {
_showPicker(context, 'A');
},
Then pass it to the _showPicker.
void _showPicker(context, id) {
...
onTap: () {
_imgFromGallery(id); // Passed 'A' in this example
Navigator.of(context).pop();
}),
...
Then,
_imgFromGallery(id) async {
final image = await Picker.pickImage(
source: ImageSource.gallery, imageQuality: 50
);
// Depends on the id, decide where and how to save the image.
switch(id) {
case 'A': setState(...); break;
case 'B': saveIntoLocal(...); break;
case 'C': uploadToServer(...); break;
....
}
}

Related

List.add not adding element to a boolean list in flutter

I have two Lists, imageFileList and values
// contains a list of image files which are captured from the camera page
List<File> imageFileList = widget.imageFileList;
// Values list is filled with boolean values which are defaulted to false and contains the same length as imageFileList
List<bool> values = widget.values;
the imageFileList gets a new File added when user selects a picture from the gallery, and i want to simultaneously add another bool entry to the values List, as such -
Future pickImage() async {
try {
final image =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return;
final imageTemp = File(image.path);
setState(() {
// adding a new image to imageFileList
imageFileList.add(imageTemp);
// adding a new bool to values List
values.add(false);
});
// rebuildAllChildren(context);
} catch (e) {
print(e);
}
}
When i use pickImage(), the file gets added to the imageFileList, but the false bool is not getting added to the values List.
debug output shows this line when i print the lengths of imageFileList and values List -
print("imagelist = " +
imageFileList.length.toString());
print("values = " +
values.length.toString());
// debug output
I/flutter (20710): imagelist = 5
I/flutter (20710): values = 4
any suggestions on what might be wrong?
here is the full code -
Widget build(BuildContext context) {
// contains a list of image files which are captured from the camera page
List<File> imageFileList = widget.imageFileList;
// Values list is filled with boolean values which are defaulted to false and contains the same length as imageFileList
List<bool> values = widget.values;
Future pickImage() async {
try {
final image =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (image == null) return;
final imageTemp = File(image.path);
setState(() {
imageFileList.add(imageTemp);
values.add(false);
});
// rebuildAllChildren(context);
} catch (e) {
print(e);
}
}
getStoragePermissionStatus() async {
await Permission.camera.request();
var status = await Permission.storage.status;
if (status.isGranted) {
log('Camera Permission: GRANTED');
setState(() {
_isStoragePermissionGranted = true;
});
// asking the user to select an image IF they grant storage permission
await pickImage();
print(_isStoragePermissionGranted);
} else {
log('Camera Permission: DENIED');
}
}
return WillPopScope(
onWillPop: (() => onWillPop(context)),
child: Scaffold(
backgroundColor: Color(lightBlueColor),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'Captures',
style: TextStyle(
fontSize: 32.0,
color: Colors.white,
),
),
),
Container(
height: returnDeviceHeight(context) / 1.2,
width: returnDeviceWidth(context),
child: ListView.builder(
itemCount: imageFileList.length,
itemBuilder: (BuildContext context, int index) {
String key = imageFileList[index].toString();
return Column(
children: <Widget>[
Container(
width: returnDeviceWidth(context) - 10,
height: returnDeviceHeight(context) / 2,
decoration: BoxDecoration(
borderRadius:
BorderRadius.all(Radius.circular(8.0)),
color: Colors.black,
border: Border.all(
color: values[index] ? Colors.green : Colors.red,
width: 4,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Center(
child: InkWell(
onTap: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) => PreviewScreen(
fileList: imageFileList,
imageFile: imageFileList[index],
),
),
);
},
child: Image.file(
imageFileList[index],
fit: BoxFit.cover,
),
),
),
),
],
),
),
Divider(
height: 2.0,
),
],
);
},
),
),
ReturnSizedBox10(),
InkWell(
onTap: () async {
await getStoragePermissionStatus();
},
child: Container(
width: returnDeviceWidth(context) - 10,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
color: Color(darkBlueColor),
),
child: Center(
child: LightBluefontstyleMont(
text: "Pick an image from gallery", size: 20),
),
),
),
InkWell(
onTap: () async {
print("imagelist = " +
imageFileList.length.toString());
print("values = " +
values.length.toString());
},
child: Container(
width: returnDeviceWidth(context) - 10,
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
color: Colors.white,
),
child: Center(
child: LightBluefontstyleMont(text: "Done", size: 20),
),
),
)
],
),
),
),
);
}
I have tried to with the setState and without it, however both times, only the imageFileList gets the new entry added.
I need to add a new entry to values List when the imageFileList gets a new entry added to it.
I suspect its to do with the widget.values being passed by pointer.
what u can do is copy the value and then assigning it to List<bool> values variable.
change this:
List<bool> values = widget.values;
to this:
List<bool> values = widget.values.toList();
Well, turns out every time I add a new image to the imageFileList, the values List gets reset; to the value it had in widget.values.
Fixed it by using initState -
late List<File> imageFileList;
late List<dynamic> values;
#override
void initState() {
// contains a list of image files which are captured from the camera page
imageFileList = widget.imageFileList;
// Values list is filled with boolean values which are defaulted to false and contains the same length as imageFileList
values = widget.values.toList();
// TODO: implement initState
super.initState();
}

Flutter | How to create arounded image?

I'm trying to find a solution for resizing an image.
The images are picked from a gallery or camera. The problem that I have Is that the image always is not sharp.
This Is How I pick the photo
void _showPickOptionsDialog(BuildContext context, UserData userData) {
final user = Provider.of<Userforid>(context, listen: false);
showDialog(
context: context,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text("Pick From Gallery"),
onTap: () {
_loadPicker(ImageSource.gallery, userData);
Navigator.pop(context);
},
),
ListTile(
title: Text("Pick from Camera"),
onTap: () {
_loadPicker(ImageSource.camera, userData);
Navigator.pop(context);
},
),
],
),
),
);
}
Future _loadPicker(ImageSource source, UserData userData) async {
final XFile file =
await picker.pickImage(source: source, imageQuality: 100);
if (this.mounted) {
// This checks if the widget is still in the tree
setState(() {
if (file != null) {
_cropImage(file, userData);
} else {
return null;
}
});
//Navigator.pop(context);
}
}
_cropImage(XFile picked, UserData userData) async {
final user = FirebaseAuth.instance.currentUser.uid;
File cropped = await ImageCropper.cropImage(
sourcePath: picked.path,
aspectRatioPresets: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio16x9,
CropAspectRatioPreset.ratio5x4
],
maxWidth: 800,
);
if (cropped != null) {
setState(() {
_pickedImage = cropped;
});
}
if (_pickedImage != null) {
final ref = FirebaseStorage.instance
.ref()
.child('user_profile_pictures')
.child(user + '.jpg');
await ref.putFile(_pickedImage);
final url = await ref.getDownloadURL();
_curenturl = url;
await DatbaseService(uid: user).updateUserData(
...);
}
}
And this is how I display them
Container(
child: ClipRRect(
borderRadius:
BorderRadius.circular(60),
child: Container(
height: 110,
width: 110,
decoration: BoxDecoration(
color: Colors.white,
),
child: _pickedImage != null
? Image.file(
_pickedImage,
fit: BoxFit.cover,
)
: userData.url != null &&
userData.url !=
"profilepictureer"
? Image.network(
userData.url,
fit: BoxFit.cover,
)
: Image.asset(
'assets/profilepictureer.png') // Your widget is here when image is no available.
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(
color: Colors.black,
width: 1)),
),
So the images are set as user profile photos. Probably a solution will be to upload rounded images like Instagram. So the question that I have is how can a user picks a normal photo from camera or gallery and upload it as rounded?
If not how to solve ghe problem then?
You can simply wrap the widget with a ClipOval with flutter.
Take a look at this doc: Flutter Document
or Try using BoxFit.fill
child: ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.network(
userData.url,
fit: BoxFit.fill,
),

Why are the picked images are not sharp?

Hey I am using a method for picking photos for user profile picture like that
void _showPickOptionsDialog(BuildContext context, UserData userData) {
final user = Provider.of<Userforid>(context, listen: false);
showDialog(
context: context,
builder: (context) => AlertDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text("Pick From Gallery"),
onTap: () {
_loadPicker(ImageSource.gallery, userData);
Navigator.pop(context);
},
),
ListTile(
title: Text("Pick from Camera"),
onTap: () {
_loadPicker(ImageSource.camera, userData);
Navigator.pop(context);
},
),
],
),
),
);
}
Future _loadPicker(ImageSource source, UserData userData) async {
final XFile file =
await picker.pickImage(source: source, imageQuality: 100);
if (this.mounted) {
// This checks if the widget is still in the tree
setState(() {
if (file != null) {
_cropImage(file, userData);
} else {
return null;
}
});
//Navigator.pop(context);
}
}
_cropImage(XFile picked, UserData userData) async {
final user = FirebaseAuth.instance.currentUser.uid;
File cropped = await ImageCropper.cropImage(
sourcePath: picked.path,
aspectRatioPresets: [
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio16x9,
CropAspectRatioPreset.ratio5x4
],
maxWidth: 800,
);
if (cropped != null) {
setState(() {
_pickedImage = cropped;
});
}
if (_pickedImage != null) {
final ref = FirebaseStorage.instance
.ref()
.child('user_profile_pictures')
.child(user + '.jpg');
await ref.putFile(_pickedImage);
final url = await ref.getDownloadURL();
_curenturl = url;
await DatbaseService(uid: user).updateUserData(
...);
}
}
And then I displaying the image like that
Container(
child: ClipRRect(
borderRadius:
BorderRadius.circular(60),
child: Container(
height: 110,
width: 110,
decoration: BoxDecoration(
color: Colors.white,
),
child: _pickedImage != null
? Image.file(
_pickedImage,
fit: BoxFit.cover,
)
: userData.url != null &&
userData.url !=
"profilepictureer"
? Image.network(
userData.url,
fit: BoxFit.cover,
)
: Image.asset(
'assets/profilepictureer.png') // Your widget is here when image is no available.
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(
color: Colors.black,
width: 1)),
),
So a user picks a photo then he can choose if he wanna crop the image and then im creating a downloadurl which im uploading into cloud firestorm and finally uploading the image into firebase cloud storage.
When ever I wanna display the photo I just calling the url.
The problem that I have is that the image looks pixaled and not sharp.
Like this
Hope anyone can help.
My 2 cents
First, try downloading the image directly from the online storage to your computer to check if it was corrupted during the upload.
Next, use the CircleAvatar widget to check whether the problem is not with the displaying part.
CircleAvatar(
radius: 50.0,
backgroundImage: _pickedImage,
)

The photo does not show up with image_picker- Flutter

I cant handle with image_picker. When I select a photo, I should see the photo instead of the avatar icon, but I don't know why it doesn't work that way. I'm new in flutter and maybe it should be solved in a different way.
The orange circle should stay and the icon should change, any advice will be great for me
Widget _avatar() {
return const CircleAvatar(
radius: 83,
backgroundColor: Colors.orange,
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 80,
child: Icon(Icons.person_outline, size: 60, color: Colors.orange),
),
);
}
File? _image;
final picker = ImagePicker();
Future getImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.gallery, maxWidth: 1800, maxHeight: 1800);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
Future getCameraImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 1800,
maxHeight: 1800,
);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
void _showPicker(BuildContext context) {
showModalBottomSheet<void>(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: Wrap(
children: <Widget>[
ListTile(
leading: new Icon(Icons.photo_size_select_large_sharp),
title: new Text('Photo Library'),
onTap: () {
getImage();
Navigator.of(context).pop();
}),
ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () {
getCameraImage();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
Widget _changeAvatarButton(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 83,
backgroundColor: Colors.orange,
child: _image == null ? _avatar() : Image.file(_image!),
),
CustomButtonText(
onPressed: () {
_showPicker(context);
},
title: 'photo',
textColor: Colors.teal),
],
);
}
Change Your CircleAvtar widget with the below one and if you don't want to show the orange circle then set the backgroundColor: _image == null ? Colors.orange : Colors.transparent.
CircleAvatar(
radius: 83,
backgroundColor: Colors.orange,
child: _image == null
? _avatar()
: ClipRRect(
borderRadius: BorderRadius.circular(83),
child: Image.file(
_image!,
height: 160, // Change the size up or down accordingly border radius
width: 160, // Change the size up or down accordingly border radius
fit: BoxFit.cover,
)),
),
It looks all fine with the state update and the image picking. What you should be paying attention at is the async functions, because you need to wait for the images before updating your widgets, and getCameraImage() and getImage() are a Future. Check if adding await solves the problem.
ListTile(
leading: new Icon(Icons.photo_size_select_large_sharp),
title: new Text('Photo Library'),
onTap: () async {
await getImage();
Navigator.of(context).pop();
}),
ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Camera'),
onTap: () async {
await getCameraImage();
Navigator.of(context).pop();
},
),

Error while trying to load an asset: FormatException: Illegal scheme character - error while using image picker

I am trying to enable to the app user to change his/her profile picture and upload it via camera or gallery, I used
the image picker package for this purpose,
this is my code snippet:
`
class ProfilePic extends StatefulWidget {
const ProfilePic({
Key key,
}) : super(key: key);
#override
_ProfilePicState createState() => _ProfilePicState();
}
class _ProfilePicState extends State<ProfilePic> {
File image = new File("");
final _picker = ImagePicker();
#override
Widget build(BuildContext context) {
return SizedBox(
height: 115,
width: 115,
child: Stack(
fit: StackFit.expand,
overflow: Overflow.visible,
children: [
CircleAvatar(
backgroundImage: AssetImage(image.uri.toFilePath()),
// child: ClipRRect(
// borderRadius: BorderRadius.circular(50),
// child: image != null
// ? Image.file(
// image,
// width: 115,
// height: 115,
// fit: BoxFit.fitHeight,
// )
// : Container(
// decoration: BoxDecoration(
// color: Colors.grey[100],
// borderRadius: BorderRadius.circular(50)),
// width: 100,
// height: 100,
// child: Icon(
// Icons.camera_alt,
// color: Colors.grey[800],
// ),
// ),
// ),
),
Positioned(
right: -16,
bottom: 0,
child: SizedBox(
height: 46,
width: 46,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50),
side: BorderSide(color: Colors.white),
),
color: Color(0xFFF5F6F9),
onPressed: () {
_showPicker(context);
},
child: SvgPicture.asset("icons/cameraIcon.svg"),
),
),
)
],
),
);
}
_imgFromCamera() async {
PickedFile pickedFile =
await _picker.getImage(source: ImageSource.camera, imageQuality: 50);
setState(() {
image = File(pickedFile.path);
});
}
_imgFromGallery() async {
PickedFile pickedFile =
await _picker.getImage(source: ImageSource.gallery, imageQuality: 50);
setState(() {
image = File(pickedFile.path);
});
}
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Container(
child: new Wrap(
children: <Widget>[
new ListTile(
leading: new Icon(Icons.photo_library),
title: new Text('Gallerie'),
onTap: () {
_imgFromGallery();
Navigator.of(context).pop();
}),
new ListTile(
leading: new Icon(Icons.photo_camera),
title: new Text('Caméra'),
onTap: () {
_imgFromCamera();
Navigator.of(context).pop();
},
),
],
),
),
);
});
}
}
`
PS: I am using Chrome for debugging.
Its select the image from the device but doesn't change the state to upload the image, am asking if it is a flutter web related problem so in a real device or emulator can work smoothly?
Any suggestion please.
AssetImage takes asset files that you have referenced in your pubspec.yaml. you should use FileImage instead if you are trying to display images from the camera or gallery.
example: FileImage(image)
You can read more here