Use device's camera for updating profile picture
This guide shows the typical interaction for updating a user's profile picture in a native app, where user can take a photo or pick an existing image from device's gallery. To see the full example in Ensemble Studio, click here (opens in a new tab).
Here's the experience we'll work toward:
1. Display user image with an icon
First, call the API that return's user image and pass the value to the Avatar widget. Using styles properties, we can display the avatar as a circle with a border.
View:
onLoad:
invokeAPI:
name: getUser
body:
Column:
styles:
mainAxis: center
children:
- Avatar:
source: ${getUser.body.results[0].picture.large}
styles:
height: 100
width: 100
borderRadius: 100
borderColor: blue
borderWidth: 2
margin: 2
API:
getUser:
uri: https://randomuser.me/api/?nat=us&randomapi
method: GET
To display an icon on top of the avatar, we use a the Stack widget and pass these children, in this order:
- Avatar
- Icon
The Stack widget renders each child on top of the previous one. By setting styles.alignChildren
to bottomRight
, we can achive the following:
- Stack:
styles:
alignChildren: bottomRight
children:
- Avatar:
source: ${getUser.body.results[0].picture.large}
styles:
height: 100
width: 100
borderRadius: 100
borderColor: blue
borderWidth: 2
margin: 2
- Icon:
name: camera_line
library: remix
styles:
size: 20
backgroundColor: white
color: blue
padding: 4
borderColor: blue
borderRadius: 200
borderWidth: 2
2. onTap, display a bottom sheet
When user taps the profile image, we want to display a bottom sheet with two buttons:
To achieve the above, first wrap the Stack widget inside a Column widget so we can add an onTop to the Column. onTap, we use showBottomModal
action to open a bottom sheet:
View:
onLoad:
invokeAPI:
name: getUser
body:
Column:
styles:
mainAxis: center
crossAxis: stretch
children:
- Column:
styles:
crossAxis: center
onTap:
showBottomModal:
widget: ProfilePhotoOptions
options:
enableDrag: false
children:
- Stack:
# ...
Note that we're passing a widget named ProfilePhotoOptions
to be rendered inside the bottom sheet.
3. Add buttons to the bottom sheet
Let's define the ProfilePhotoOptions widget, which includes two buttons:
ProfilePhotoOptions:
body:
Column:
styles:
crossAxis: stretch
mainAxisSize: min
gap: 24
padding: 24 24 ${device.safeAreaBottom} 24
children:
- Button:
label: Take photo
- Button:
label: Pick from gallery
Note a few styling configurations:
- Buttons are placed inside a Column with
crossAxis: stretch
. This ensures the buttons width will stretch across the screen. - This Column also includes
mainAxisSize: min
to ensure the column just takes the space required by the children. - For padding, we use 24 on top, right, and left. For bottom padding, we use
${device.safeAreaBottom}
so that depending on the device, enough space is added to the bottom of the column.
4. Add action to Take Photo buttom
Here, we use the openCamera
action with following configurations:
- Button:
label: Take photo
onTap:
openCamera:
id: profilePhoto
options:
default: true
allowGalleryPicker: true
allowCameraRotate: true
allowFlashControl: true
enableMicrophone: false
preview: false
maxCount: 1
mode: photo
onComplete:
# Either upload the photo, or navigate to a screen where user can crop the photo
# for both options, use the id of the action to access the file: ${profilePhoto.files[0].path}
# navigateScreen:
# name: ProfileImageCropper
# inputs:
# newProfileImage: ${profilePhoto.files[0].path}
This configuration uses the device's native camera functionality, and limits it to one image.
5. Add action to Pick from Gallery buttom
Here, we use the pickFiles
action with following configurations:
- Button:
label: Pick from gallery
styles:
height: 50
onTap:
pickFiles:
source: gallery
id: filepicker
allowMultiple: false
allowedExtensions:
- png
- jpeg
- jpg
onComplete:
# TODO - you can either use the selected photo, or navigate to a screen where user can crop the photo
# navigateScreen:
# name: ProfileImageCropper
# inputs:
# newProfileImage: ${filepicker.files[0].path}
This configuration uses the device's native gallery, and limits it to one image.
To see the full example in Ensemble Studio, click here (opens in a new tab).