I am creating a app for iMessage only, searching images & populating a UICollectionView, the problem is that I cannot select the items. I need to be able to tap/select an item so it can be passed as the message layout & then send it but that part seems to be not working.
class MessagesViewController: MSMessagesAppViewController, UISearchBarDelegate {
var images_results: [Result] = []
let searchbar = UISearchBar()
private var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
searchbar.delegate = self
collectionView?.delegate = self
view.addSubview(searchbar)
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 6
layout.minimumInteritemSpacing = 2
let itemSize = view.frame.size.width/3.5
layout.itemSize = CGSize(width: itemSize, height: itemSize)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(ImageCollectionViewCell.self, forCellWithReuseIdentifier: ImageCollectionViewCell.identifier)
collectionView.allowsSelection = true
collectionView.dataSource = self
view.addSubview(collectionView)
collectionView.backgroundColor = .systemBackground
self.collectionView = collectionView
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
searchbar.frame = CGRect(x: 10, y: view.safeAreaInsets.top, width: view.frame.size.width-20, height: 50)
collectionView?.frame = CGRect(x: 7, y: view.safeAreaInsets.top+55, width: view.frame.size.width-15, height: view.frame.size.height-55)
searchbar.placeholder = "Search Images"
}
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
requestPresentationStyle(.expanded)
return true
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchbar.resignFirstResponder()
if let text = searchbar.text {
images_results = []
collectionView?.reloadData()
fetchPhotos(query: text)
}
}
func fetchPhotos(query: String) {
let urlString = "https://api.url.com"
guard let url = URL(string: urlString) else { return }
let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let data = data, error == nil else { return }
do {
let jsonResult = try JSONDecoder().decode(APIResponse.self, from: data)
print("GOT DATA")
DispatchQueue.main.async {
self?.images_results = jsonResult.results
self?.collectionView?.reloadData()
}
} catch {
print("WE GOT AN ERROR: \(error)")
}
}
task.resume()
}
// MARK: - Conversation Handling
override func willBecomeActive(with conversation: MSConversation) {
fetchPhotos(query: ["animals", "fruits", "cars", "memes", "houses", "ocean"].randomElement()!)
// Called when the extension is about to move from the inactive to active state.
// This will happen when the extension is about to present UI.
// Use this method to configure the extension and restore previously stored state.
}
override func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) {
if presentationStyle == .expanded {
searchbar.becomeFirstResponder()
}
// Called after the extension transitions to a new presentation style.
// Use this method to finalize any behaviors associated with the change in presentation style.
}
}
extension MessagesViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.item)
}
}
extension MessagesViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images_results.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let imageURLString = images_results[indexPath.row].urls.thumb
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageCollectionViewCell.identifier, for: indexPath) as? ImageCollectionViewCell else {
return UICollectionViewCell()
}
cell.configure(with: imageURLString)
return cell
}
}
//Custom Cell
class ImageCollectionViewCell: UICollectionViewCell {
static let identifier = "ImageCollectionViewCell"
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.clipsToBounds = true
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = 4
return imageView
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.addSubview(imageView)
}
required init? (coder: NSCoder) {
fatalError ()
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = contentView.bounds
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
}
override func awakeFromNib() {
super.awakeFromNib()
print("awakefromnib")
selectedItem()
}
func configure(with urlString: String) {
guard let url = URL(string: urlString) else {
return
}
URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
guard let data = data, error == nil else { return }
DispatchQueue.main.async {
let image = UIImage(data: data)
self?.imageView.image = image
}
}.resume()
}
func selectedItem() {
self.imageView.alpha = 0.7
}
}
This is the only part that is not working:
extension MessagesViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
...code for preparing image for message, right now I only have a print statement which is doing nothing ...
}
}
I should be able to select an image to add to message but is not working
You are assigning the the delegate before the collection view was initialized.
Move the collection view initializer to the view top of the viewDidLoad like so:
override func viewDidLoad() {
super.viewDidLoad()
self.collectionView = UICollectiinView(…)
self.collectionView?.delegate = self
.
.
.
}