La photo de profil peut être, par exemple, dans une cellule de collection, ou associée à un bouton, ou encore une simple image. L'action qui va déclencher l'ajout de la photo est la sélection de la cellule, ou l'appui sur le bouton, ou le touché de la vue. Dans notre exemple, c'est le touché de la vue.
Deux possibilités, soit ajouter une méthode existante, en override "touchesBegan", soit ajouter un TapGestureRecognizer sur l'image, le relier au controller en "@IBAction" (dans le story, icône dans la barre du haut du view controller) et implémenter l'action.
Ici, "touchesBegan" est utilisée,
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// on vérifie s'il y a un touché = le tableau de touché "Set<UITouch>" n'est pas vide = au moins 1 touché
guard let touch = touches.first else { return }
//on vérifie qu'il y a un user et que c'est bien moi pour changer le profil !!!
guard let myUser = user else { return }
guard let myId = FireAuth().myId() else { return }
guard myId == myUser.uid else { return }
//on définit la zône où le touché est actif
if touch.view == profilImage {
//action
} else {
return
}
}
Pour que le geste soit reconnu par la vue, dans le storyboard, sélectionner la vue, et dans inspecteur d'attributs, cocher la case "User Interaction Enabled". Ou ajouter la propriété à la vue :
//Autorise les interactions avec l'utilisateur
imageView.isUserInteractionEnabled = true
En appuyant sur la vue, une action est déclenchée. Cette action fait apparaître une alerte donnant le choix de prendre une photo avec l'appareil, ou en sélectionner une dans l'album.
Il est possible d'accéder directement à l'album, (voir annexe à la fin).
Pour cela un "ImagePickerController" est nécessaire, ainsi qu'un "UINavigationControllerDelegate". Ajouter en extension :
extension ProfilController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//imagePicker a un tableau d'image = info
//l'image est soit éditée(une partie avec le zoom), ou originale
if let editedImage = info[.editedImage] as? UIImage {
profilImage.image = editedImage.withRenderingMode(.alwaysOriginal)
} else if let originalImage = info[.originalImage] as? UIImage {
profilImage.image = originalImage.withRenderingMode(.alwaysOriginal)
}
dismiss(animated: true, completion: nil)
}
}
Définition de l'alerte :
func profilImageAlert() {
let photoSourceController = UIAlertController(title: "", message: "Choississez votre image", preferredStyle: .actionSheet)
let cameraAction = UIAlertAction(title: "Appareil photo", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true //permet de zoomer l'image
imagePicker.sourceType = .camera
self.present(imagePicker, animated: true, completion: nil)
}
}
let albumPhotoAction = UIAlertAction(title: "Album photo", style: .default) { (action) in
if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true //permet de zoomer l'image
imagePicker.sourceType = .photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
}
photoSourceController.addAction(cameraAction)
photoSourceController.addAction(albumPhotoAction)
present(photoSourceController, animated: true, completion: nil)
}
Pour finir appeler cette méthode dans "touchesBegan" au niveau de l'action.
if touch.view == profilImage {
//action
profilImageAlert()
Il reste à compléter le fichier "Info.plist", en ajoutant deux autorisations "key/Value" pour l'accès à l'album photo et à l'appareil photo
ANNEXE
Accéder directement à l'album photo, sans popup préalable.
L'extension ProfilController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {} reste inchangée.
A la place de la méthode "profilImageAlert()", implémenter une nouvelle méthode, ou implémenter l'IBAction du tapgestureRecognizer
func profilImage() {
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
present(imagePickerController, animated: true, completion: nil)
Ajouter une image dans le simulateur
Quand l'application est lancée dans le simulateur, pour ajouter une image stockée sur le mac, il suffit de faire glisser cette image sur le simulateur, à l'emplacement prévue de l'image. Cette image est ajoutée à l'album. En revenant sur l'application dans le simulateur, l'image peut être sélectionnée.
Quand on utilise des images (profile, publications, etc...) stockées sur une base de données, il peut être intéressant de les garder en cache dans l'appareil, pour éviter de les télécharger à chaque fois (temps d'attente, et coûts).
On peut utiliser la librairie "SDWebImage" de CocoaPods. (voir story suivante : "FIREBASE CRUD image en cache")