This is a widget for showing a profile avatar, along with an edit button which lunches the camera. If there’s no photo to be loaded a placeholder consisting of an x amount of characters from the user’s name is going to be shown.
Dependencies
Add the following packages in the pubspec.yaml first.
- image_picker: ^version
and run the pub get command from the terminal.
Usage
Example usage with lists:
Center(
child: ProfilePicture(
photoUrl: widget.profile.avatar,
username: widget.profile.name,
)),
Parameters
@photoUrl : Optional. The link to an existing profile picture @assetImage : Optional. Placeholder (currently not in use) @username : Mandatory. Used for creating a placeholder from the first x letters. @setFileCallback : Optional. The function to be called once the new avatar is selected to pass it back to the parent (in order to upload it to the backend).
Widget
class ProfilePicture extends StatefulWidget {
ProfilePicture(
{this.photoUrl,
this.assetImage = './lib/assets/logo.png',
this.username,
this.setFileCallback});
final String photoUrl;
final String assetImage;
final String username;
final Function(String) setFileCallback;
@override
_ProfilePictureState createState() => _ProfilePictureState();
}
class _ProfilePictureState extends State<ProfilePicture> {
PickedFile _imageFile;
dynamic _pickImageError;
String _retrieveDataError;
// the number of characters used for the placeholder image
int numCharPlaceholder = 2;
@override
Widget build(BuildContext context) {
final ImagePicker _picker = ImagePicker();
void _onImageButtonPressed(ImageSource source,
{BuildContext context}) async {
try {
final pickedFile = await _picker.getImage(
source: source,
);
setState(() {
_imageFile = pickedFile;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
}
Future<void> retrieveLostData() async {
final LostData response = await _picker.getLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
setState(() {
_imageFile = response.file;
});
} else {
_retrieveDataError = response.exception.code;
}
}
Text _getRetrieveErrorWidget() {
if (_retrieveDataError != null) {
final Text result = Text(_retrieveDataError);
_retrieveDataError = null;
return result;
}
return null;
}
_buildStringPlaceholder() {
return widget.username != null
? CircleAvatar(
backgroundColor: Colors.lightBlue.shade50,
child: Text(widget.username
.substring(0, numCharPlaceholder)
.toUpperCase()),
radius: Dimens.avatarBig,
)
: CircleAvatar(
backgroundColor: Colors.lightBlue.shade50,
child: Text(Strings.appName
.substring(0, numCharPlaceholder)
.toUpperCase()),
radius: Dimens.avatarBig,
);
}
Widget _previewImage() {
final Text retrieveError = _getRetrieveErrorWidget();
if (retrieveError != null) {
return retrieveError;
}
if (_imageFile != null) {
if (kIsWeb) {
// Why network?
// See https://pub.dev/packages/image_picker#getting-ready-for-the-web-platform
return CircleAvatar(
backgroundImage: NetworkImage(_imageFile.path),
radius: Dimens.avatarBig,
);
} else {
return Semantics(
child: CircleAvatar(
backgroundImage: FileImage(File(_imageFile.path)),
radius: Dimens.avatarBig,
),
label: 'image_picker_picked_image');
}
} else {
if (_pickImageError != null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Pick image error: $_pickImageError')));
}
return widget.photoUrl != null && widget.photoUrl.isNotEmpty
? CircleAvatar(
backgroundImage: NetworkImage(widget.photoUrl),
radius: Dimens.avatarBig,
)
: _buildStringPlaceholder();
}
}
_buildAvatar() {
return Container(
child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return widget.photoUrl != null &&
widget.photoUrl.isNotEmpty
? CircleAvatar(
backgroundImage: NetworkImage(widget.photoUrl),
radius: Dimens.avatarBig,
)
: _buildStringPlaceholder();
case ConnectionState.done:
if (_imageFile != null) {
widget.setFileCallback(_imageFile.path);
}
return _previewImage();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: _previewImage(),
);
}
return Container(
child: Stack(
children: <Widget>[
_buildAvatar(),
Positioned(
top: 0,
right: 0,
child: IconButton(
icon: new Icon(Icons.edit),
onPressed: () {
_onImageButtonPressed(ImageSource.camera,
context: context); //gallery: ImageSource.gallery
},
),
),
],
),
);
}
}