How to create a custom AccessoryView for Text and TextField views with Collection View inside. Telegram-Drawing-Text-Editing, ep. 2
This article is the part of the project Telegram-Like-Drawing-Text-Editing. But you can find this information useful for your your own code.
The final result as follows:
Let’s get started.
The idea of custom toolbar is straightforward, is simply a UIView. So there’s no need to subclass Toolbar, because it has those restrictions we’re trying to avoid. So, just a UIView.
But we need a collection view, which is managed by UICollectionViewController. So, to make this collection view works we need to add a collection view as a child of a view of our current view controller that possesses text view we want to have our toolbar.
I’ve initialized toolbar view as usual view. Intialization looks poor, because we can’t do more at this point.
let toolbar: UIView = {
let view = UIView()
view.backgroundColor = .systemGray6
return view
}()
Add collection controller too, to avoid difficulties in the future. We pass default layout because inside collectionViewController’s implementation we have a method that builds proper layout.
let collectionController = IPAvailableFontsCollectionViewController(collectionViewLayout: UICollectionViewLayout())
I move setup to a distinct function.
Interesting points are:
1. We add collectionController as a child to our current view controller.
2. Tell the system that collectionController moved to parent.
3. Set the delegate(this is not necessary if your collection view doesn’t have an ability to interact with cells)
4. And add collectionController’s collection view to toolbar.
func setupToolbar() {
toolbar.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 50)
collectionController.collectionView!.translatesAutoresizingMaskIntoConstraints = false
// 1
self.addChild(collectionController)
// 2
collectionController.didMove(toParent: self)
// 3
collectionController.delegate = self
toolbar.addSubview(alignmentChangeButton)
toolbar.addSubview(fillChangeButton)
// 4
toolbar.addSubview(collectionController.collectionView)
NSLayoutConstraint.activate([
alignmentChangeButton.topAnchor.constraint(equalTo: toolbar.topAnchor, constant: 5),
alignmentChangeButton.leadingAnchor.constraint(equalTo: toolbar.leadingAnchor, constant: 5),
alignmentChangeButton.bottomAnchor.constraint(equalTo: toolbar.bottomAnchor, constant: -5),
fillChangeButton.topAnchor.constraint(equalTo: toolbar.topAnchor, constant: 5),
fillChangeButton.leadingAnchor.constraint(equalTo: alignmentChangeButton.trailingAnchor, constant: 5),
fillChangeButton.bottomAnchor.constraint(equalTo: toolbar.bottomAnchor, constant: -5),
collectionController.collectionView.topAnchor.constraint(equalTo: toolbar.topAnchor, constant: 5),
collectionController.collectionView.leadingAnchor.constraint(equalTo: fillChangeButton.trailingAnchor, constant: 15),
collectionController.collectionView.trailingAnchor.constraint(equalTo: toolbar.trailingAnchor, constant: -5),
collectionController.collectionView.bottomAnchor.constraint(equalTo: toolbar.bottomAnchor, constant: -5)
])
}
The last thing you need to make is to asign the toolbar we’ve just setup to a accessoryView of textView.
textView.inputAccessoryView = toolbar
If you’re curious about how I’ve made collection view with compositional layout which has dynamic width cells, I encourage you to check this post.