Round cells inside a set view
Attaining the objective is comparatively straightforward, but when you do not know what is going on on within the background it is would possibly gona be more durable than you’d suppose first. So let’s create a brand new challenge add a storyboard with a UICollectionViewController
, drag a UIImageView
contained in the cell, resize it, add some constraints, set the cell identifier.
It ought to look one thing just like the picture above. Nothing particular only a easy UI for our instance software. Now seek for some random picture, add it to the challenge and let’s do some actual coding. First I am going to present you the little trick inside the cell subclass.
class Cell: UICollectionViewCell {
@IBOutlet weak var imageView: UIImageView!
override var bounds: CGRect {
didSet {
self.layoutIfNeeded()
}
}
override func awakeFromNib() {
tremendous.awakeFromNib()
self.imageView.layer.masksToBounds = true
}
override func layoutSubviews() {
tremendous.layoutSubviews()
self.setCircularImageView()
}
func setCircularImageView() {
self.imageView.layer.cornerRadius = CGFloat(roundf(Float(self.imageView.body.measurement.width / 2.0)))
}
}
Are you able to see it? Sure, you need to override the bounds property. As the following step we have now to jot down the controller class with some fundamental knowledge supply for the gathering view and with the right assist for the rotation strategies. 🤓
class ViewController: UICollectionViewController {
override func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection part: Int) -> Int {
return 30
}
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.imageView.picture = UIImage(named: "Instance.jpg")
cell.imageView.backgroundColor = .lightGray
return cell
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
tremendous.traitCollectionDidChange(previousTraitCollection)
guard
let previousTraitCollection = previousTraitCollection,
self.traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass ||
self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass
else {
return
}
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.reloadData()
}
override func viewWillTransition(to measurement: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
tremendous.viewWillTransition(to: measurement, with: coordinator)
self.collectionView?.collectionViewLayout.invalidateLayout()
coordinator.animate(alongsideTransition: { context in
}, completion: { context in
self.collectionView?.collectionViewLayout.invalidateLayout()
self.collectionView?.visibleCells.forEach { cell in
guard let cell = cell as? Cell else {
return
}
cell.setCircularImageView()
}
})
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
format collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.body.measurement.width/3.0 - 8,
peak: collectionView.body.measurement.width/3.0 - 8)
}
}
If you’re conversant in assortment views, you would possibly ask why am I doing this tutorial? It is so easy. It simply works, proper? No, really with out the overridden bounds
property the instance would look one thing like this on the left facet. 😢
Humorous, huh? The picture on the best facet is the precise consequence with the overridden bounds, that is the anticipated behaviour. Scrolling and rotation goes to be actually unusual when you do not override bounds and you do not reset the cornerRadius property for the seen views. You would possibly ask: however why? 🤔
Layers, springs & struts and a few rationalization
Apple nonetheless has “Springs & Struts” primarily based code inside UIKit. Which means body and certain calculations are occurring within the underlying system and the constraint system is attempting to work onerous as nicely to determine the right measures.
“Springs & Struts” must die!
Whereas there’s an init(body:)
methodology, or a required init(coder:)
these format issues will suck as hell. I actually like Interface Builder, however till we can’t get a high quality instrument to create nice consumer interfaces IB goes to be simply one other layer of attainable bugs.
This subject will not even be there when you create the cell from code solely utilizing autolayout constraints or format anchors! It is as a result of IB creates the cell primarily based on the body you gave in when you designed your prototype. However when you neglect init(body:)
and also you simply create a brand new UIImageView
occasion and let auto format do the onerous work, the format system will remedy every little thing else. Verify this.
class Cell: UICollectionViewCell {
weak var imageView: UIImageView!
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been carried out")
}
override init(body: CGRect) {
tremendous.init(body: body)
self.translatesAutoresizingMaskIntoConstraints = false
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(imageView)
self.imageView = imageView
self.imageView.topAnchor.constraint(equalTo: self.topAnchor)
self.imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor)
self.imageView.leadingAnchor.constraint(equalTo: self.leadingAnchor)
self.imageView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
}
override func layoutSubviews() {
tremendous.layoutSubviews()
self.imageView.layer.masksToBounds = true
self.imageView.layer.cornerRadius = CGFloat(roundf(Float(self.imageView.body.measurement.width/2.0)))
}
}
Clearly it’s a must to write extra code, register your cell class manually contained in the controller class and also you additionally need to override the layoutSubviews methodology contained in the cell, however it’ll work as it’s anticipated. 🙄
self.collectionView?.register(Cell.self, forCellWithReuseIdentifier: "Cell")
Anyway, after you register the programmatically created cell you may have a pleasant approach of displaying round photographs. Utilizing this system is kind of difficult, however it positively works in each case. You’ll be able to obtain the instance from The.Swift.Dev. tutorials on github.