I am trying to set up images in the horizontal alignment in collectionView, but it's not working properly. Please check the attached screenshot.
View Controller Code:-
import UIKit
class ViewController: UIViewController,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout {
@IBOutlet weak var texting1: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
self.texting1.register(UINib(nibName:"CollectionViewCell1", bundle: nil), forCellWithReuseIdentifier: "CollectionViewCell1")
self.texting1.delegate = self
self.texting1.dataSource = self
texting1.backgroundColor = .red
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell1", for: indexPath) as! CollectionViewCell1
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.view.frame.width, height: 120)
}
}
If we instead use negative constants:
NSLayoutConstraint.activate([
red.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0),
green.leadingAnchor.constraint(equalTo: red.trailingAnchor, constant: -20.0),
blue.leadingAnchor.constraint(equalTo: green.trailingAnchor, constant: -20.0),
])
it can look like this:
So we can create a custom UIView
subclass that handles all of that for us -- such as this:
class OverlapView: UIView {
public var overlap: CGFloat = -30 { didSet { setNeedsLayout() } }
public var cellViews: [UIView] = [] {
didSet {
// clear out any existing subviews
subviews.forEach { v in
v.removeFromSuperview()
}
cellViews.forEach { v in
// in case it wasn't set by the caller
v.translatesAutoresizingMaskIntoConstraints = false
addSubview(v)
// center it vertically
v.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
// we want the overlap to go from left-to-right
sendSubviewToBack(v)
}
setNeedsLayout()
}
}
private var horizontalConstraints: [NSLayoutConstraint] = []
override func layoutSubviews() {
super.layoutSubviews()
guard cellViews.count > 0 else { return }
// de-activate any existing horizontal constraints
NSLayoutConstraint.deactivate(horizontalConstraints)
var prevView: UIView!
cellViews.forEach { v in
// if it's the first one
if prevView == nil {
horizontalConstraints.append(v.leadingAnchor.constraint(equalTo: leadingAnchor))
} else {
horizontalConstraints.append(v.leadingAnchor.constraint(equalTo: prevView.trailingAnchor, constant: overlap))
}
prevView = v
}
// constrain last view's trailing
horizontalConstraints.append(prevView.trailingAnchor.constraint(equalTo: trailingAnchor))
// activate the udpated constraints
NSLayoutConstraint.activate(horizontalConstraints)
}
}
Here's a sample controller demonstrating that:
class OverlapTestVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let testView = OverlapView()
testView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(testView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
testView.topAnchor.constraint(equalTo: g.topAnchor, constant: 40.0),
testView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 16.0),
testView.heightAnchor.constraint(equalToConstant: 70.0),
// no trailing or width constraint
// width will be determined by the number of "cells"
])
// let's add 6 "cells" -- one for each color
let colors: [UIColor] = [
.systemRed, .systemGreen, .systemBlue,
.systemYellow, .systemCyan, .magenta,
]
var cellViews: [UIView] = []
colors.forEach { c in
if let img = UIImage(systemName: "person.crop.circle") {
let imgView = UIImageView(image: img)
imgView.tintColor = c
imgView.backgroundColor = .white
imgView.translatesAutoresizingMaskIntoConstraints = false
// let's use a 60x60 image view
imgView.widthAnchor.constraint(equalToConstant: 60.0).isActive = true
imgView.heightAnchor.constraint(equalTo: imgView.widthAnchor).isActive = true
// we want "round" views
imgView.layer.cornerRadius = 30.0
imgView.layer.masksToBounds = true
cellViews.append(imgView)
}
}
testView.cellViews = cellViews
// we can change the overlap value here if we don't want to use
// our custom view's default
// for example:
//testView.overlap = -40.0
// so we can see the framing
testView.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
}
}
Output looks like this:
(We gave the custom view itself a light gray background so we can see its frame.)