I couldn't find much of use in the docs, and the sample project in Swift only had hardcoded avatars so that wasn't much help either. I also saw this question but that example was also not applicable in my situation.
I have my user sign in with Facebook, and a graph request grabs their profile picture which is then stored in Firebase and a User object as a string (the URL path to the image I mean).
This is my cellForItem
function
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAt: indexPath) as! JSQMessagesCollectionViewCell
let message = messages[indexPath.item]
if message.senderId == senderId {
cell.textView?.textColor = UIColor.white
} else {
cell.textView?.textColor = UIColor.black
}
return cell
}
And this is where I should be setting the avatars:
override func collectionView(_ collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAt indexPath: IndexPath!) -> JSQMessageAvatarImageDataSource! {
let message = messages[indexPath.item]
if let messageID = message.senderId {
let users = [User]()
let userProfilePictures = users[indexPath.row].profilePicture
}
return ????
}
Anyone know how I can get the profile pictures set to the correct avatars?
EDIT: This is my image caching code:
let imageCache = NSCache<NSString, UIImage>()
extension UIImageView {
func loadImageUsingCacheWithUrlString(_ urlString: String) {
self.image = nil
// Check cache for image first
if let cachedImage = imageCache.object(forKey: urlString as NSString) {
self.image = cachedImage
return
}
// Otherwise fire off a new download
Alamofire.request(urlString)
.responseImage { response in
if let downloadedImage = response.result.value {
// image is here.
imageCache.setObject(downloadedImage, forKey: urlString as NSString)
self.image = downloadedImage
}
}
}
}
Ya, What you are looking for is the 'JSQMessagesAvatarImageFactory' Documentation Link
Since you have your userProfilePicture
Then you just need to get the image data for that url. You can do this a number of ways I personally love to use a framework that handles catching for you. SDWebImage or AlamofireImage or how ever else you want to get that data.
I like AlimofireImage
so that is what I will demonstrate here. To make it so that I do not have to keep making downloading request for each cell I save them in a dictionary using the senderID
as a key. If the dictionary entry is there I don't make the request. Define your dictionary.
var avatarDictionary: [String:UIImage] = [:]
Then after retrieving all the messages for the conversation call getAllAvatars()
func getAllAvatars() {
for message in messages {
guard let key = message.senderID else { return }
if avatarDictionary[key] == nil {
try? _ = imageDownloader?.download(URLRequest(url: API.userPhoto(userID: key).asURL()), completion: { (response) in
guard let image = response.result.value else { return }
self.avatarDictionary[key] = image
self.collectionView.reloadData()
})
}
}
}
API.userPhoto(userID: key).asURL()
is the url to your image data source so this is what you will change for the url you have.
There are a few other methods you could also take a look into. I made my own function to give me a defaultAvatar
for users with no image. It looks like this
func blankAvatar(message: Message) -> JSQMessageAvatarImageDataSource {
return JSQMessagesAvatarImageFactory.avatarImage(withUserInitials: initialsFrom(firstName: message.fistName, lastName: message.lastName), backgroundColor: UIColor.gray, textColor: UIColor.white, font: UIFont.systemFont(ofSize: 14), diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
}
Then you can return a image if it is there or a blank avatar if not from the avatarImageDataForItemAt
method
return avatarDictionary[id] == nil ? blankAvatar(message: message) : JSQMessagesAvatarImageFactory.avatarImage(with: avatarDictionary[id], diameter: UInt(kJSQMessagesCollectionViewAvatarSizeDefault))
Also don't forget to set the size of the avatars for the collectionView
collectionView?.collectionViewLayout.incomingAvatarViewSize = avatarSize
collectionView?.collectionViewLayout.outgoingAvatarViewSize = avatarSize
or they wont show at all.
Let me know if you need more help 🖖🏽.