I need to disallow Collection View selection, but left CV's header enabled?
Both methods block header. How to enable it?
CollectionView.isUserInteractionEnabled = false
or
CollectionView.allowsSelection = false
Here is UICollectionReusableView:
final class HeaderCollectionReusableView: UICollectionReusableView {
override init(frame: CGRect) {
super.init(frame: .zero)
addSubView()
setupLayout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static let headerIdentifier = "HeaderCollectionReusableView"
private func addSubView() {
addSubview(collectionView)
}
public lazy var collectionView: UICollectionView = {
var flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.itemSize = CGSize(width: UIScreen.main.bounds.size.width / 3.5, height: UIScreen.main.bounds.size.width / 3)
flowLayout.minimumLineSpacing = 12
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
var view = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
view.register(cell: CollectionViewCell.self)
view.backgroundColor = .clear
view.showsHorizontalScrollIndicator = false
view.showsVerticalScrollIndicator = false
view.contentInsetAdjustmentBehavior = .automatic
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private func setupLayout() {
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: topAnchor),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
collectionView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.size.width / 3),
])
}
}
This is horizontal CV embedded in other vertical CV's header.
I need to disable vertical CV but left enabled horizontal CV in vertical CV' header )
To block I used CollectionView.isUserInteractionEnabled = false and it blocks everything even header.
I tried CollectionView.allowsSelection = false and it blocks CV and doesn't block header!
It works.
Before I just didn't pay attention that .allowSelection doesn't block header .
Related
I am trying to resize my UIImageView as a circle, however; every time I try to resize the UIImageView, which is inside a StackView along with the UILabel, I keep on ending up with a more rectangular shape. Can someone show me where I am going wrong I have been stuck on this for days? Below is my code, and what it's trying to do is add the image with the label at the bottom, and the image is supposed to be round, and this is supposed to be for my collection view controller.
custom collection view cell
import UIKit
class CarerCollectionViewCell: UICollectionViewCell {
static let identifier = "CarerCollectionViewCell"
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0, width: 20, height: 20);
//imageView.center = imageView.superview!.center;
imageView.contentMode = .scaleAspectFill
imageView.layer.borderWidth = 4
imageView.layer.masksToBounds = false
imageView.layer.borderColor = UIColor.orange.cgColor
imageView.layer.cornerRadius = imageView.frame.height / 2
return imageView
}()
private let carerNamelabel: UILabel = {
let carerNamelabel = UILabel()
carerNamelabel.layer.masksToBounds = false
carerNamelabel.font = .systemFont(ofSize: 12)
carerNamelabel.textAlignment = .center
carerNamelabel.layer.frame = CGRect(x: 0, y: 0, width: 50, height: 50);
return carerNamelabel
}()
private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.layer.masksToBounds = false
stackView.axis = .vertical
stackView.alignment = .center
stackView.backgroundColor = .systemOrange
stackView.distribution = .fillProportionally
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
configureContentView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private func configureContentView() {
imageView.clipsToBounds = true
stackView.clipsToBounds = true
carerNamelabel.clipsToBounds = true
contentView.addSubview(stackView)
configureStackView()
}
private func configureStackView() {
allContraints()
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(carerNamelabel)
}
private func allContraints() {
setStackViewConstraint()
}
private func setStackViewConstraint() {
stackView.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: contentView.heightAnchor).isActive = true
stackView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
}
public func configureImage(with imageName: String, andImageName labelName: String) {
imageView.image = UIImage(named: imageName)
carerNamelabel.text = labelName
}
override func layoutSubviews() {
super.layoutSubviews()
stackView.frame = contentView.bounds
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
carerNamelabel.text = nil
}
}
Below here is my code for the CollectionViewControler
custom collection view
import UIKit
class CarerViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 120, height: 120)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(CarerCollectionViewCell.self, forCellWithReuseIdentifier: CarerCollectionViewCell.identifier)
collectionView.showsVerticalScrollIndicator = false
collectionView.backgroundColor = .clear
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
// Layout constraints for `collectionView`
NSLayoutConstraint.activate([
collectionView.widthAnchor.constraint(equalTo: view.widthAnchor),
collectionView.heightAnchor.constraint(lessThanOrEqualTo: view.heightAnchor, constant: 600),
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor)
])
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CarerCollectionViewCell.identifier, for: indexPath) as! CarerCollectionViewCell
cell.configureImage(with: "m7opt04g_ms-dhoni-afp_625x300_06_July_20", andImageName: "IMAGE NO. 1")
return cell
}
}
Can somebody show or point to me what I am doing wrong, thank you
This is what I am trying to achieve
UIStackView could be tricky sometimes, you can embed your UIImageView in a UIView, and move your layout code to viewWillLayoutSubviews(), this also implys for the UILabel embed that also inside a UIView, so the containers UIViews will have a static frame for the UIStackViewto be layout correctly and whats inside them will only affect itself.
I'm trying to figure out is it possible for UICollectionView to calculate it's own height using autolayout? My custom cells are built on autolayout and the UICollectionViewFlowLayout.automaticSize property for itemSize seems to be working, but the size of UICollectionView itself should be set. I believe that this is normal behavior, since the collection can have bigger size than it's cells, but maybe it is possible to make height of the content view of UICollectionView to be equal to cell with some insets?
Here is the code for test UIViewController with UICollectionView
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 100)
layout.itemSize = UICollectionViewFlowLayout.automaticSize
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
if let collectionView = collectionView {
collectionView.showsHorizontalScrollIndicator = false
collectionView.isPagingEnabled = true
collectionView.register(CollectionViewCell.self,
forCellWithReuseIdentifier: "CollectionViewCell")
collectionView.backgroundColor = .clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
collectionView.delegate = self
collectionView.dataSource = self
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor),
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor),
// I want to get rid of this constraint
collectionView.heightAnchor.constraint(equalToConstant: 200)
])
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell",
for: indexPath) as? CollectionViewCell else {
return UICollectionViewCell()
}
return cell
}
}
And for custom cell
final class CollectionViewCell: UICollectionViewCell {
var mainView = UIView()
var bigView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .yellow
return view
}()
var label: UILabel = {
let label = UILabel()
label.text = "Here is text"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var anotherLabel: UILabel = {
let label = UILabel()
label.text = "Here may be no text"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let inset: CGFloat = 16.0
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(mainView)
mainView.translatesAutoresizingMaskIntoConstraints = false
mainView.backgroundColor = .white
addSubview(bigView)
addSubview(label)
addSubview(anotherLabel)
NSLayoutConstraint.activate([
mainView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width),
mainView.topAnchor.constraint(equalTo: topAnchor),
mainView.leftAnchor.constraint(equalTo: leftAnchor),
mainView.rightAnchor.constraint(equalTo: rightAnchor),
mainView.bottomAnchor.constraint(equalTo: bottomAnchor),
bigView.topAnchor.constraint(equalTo: mainView.topAnchor, constant: inset),
bigView.leftAnchor.constraint(equalTo: mainView.leftAnchor, constant: inset),
bigView.rightAnchor.constraint(equalTo: mainView.rightAnchor, constant: -inset),
bigView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor, constant: -inset),
label.topAnchor.constraint(equalTo: bigView.topAnchor, constant: inset),
label.leftAnchor.constraint(equalTo: bigView.leftAnchor, constant: inset),
label.rightAnchor.constraint(equalTo: bigView.rightAnchor, constant: -inset),
anotherLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: inset),
anotherLabel.leftAnchor.constraint(equalTo: bigView.leftAnchor, constant: inset),
anotherLabel.rightAnchor.constraint(equalTo: bigView.rightAnchor, constant: -inset),
anotherLabel.bottomAnchor.constraint(equalTo: bigView.bottomAnchor, constant: -inset)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And maybe someone, who knows the answer also could tell whether it's possible to later put this paging collection into UITalbleViewCell and make size of the cell change with selected item in the collection? I provide screenshot of the collection I'm trying to make:
Item's without second text label will have smaller height, than items on the picture
Screenshot
Solution 1:
Get collection view content size from collectionViewLayout :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Set your collection view height here.
let collectionHeight = self.yourCollectionView.collectionViewLayout.collectionViewContentSize.height
}
Solution 2:
Use KVO.
// Register observer
self.yourCollectionView.addObserver(self, forKeyPath: "contentSize", options: [.new, .old, .prior], context: nil)
#objc override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "contentSize" {
// content size changed. Set your collection view height here.
let contentSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
print("contentSize:", contentSize)
}
}
// Remove register observer
deinit {
self.yourCollectionView.removeObserver(self, forKeyPath: "contentSize")
}
Solution 3:
Assign this class to UICollectionView. If you set height constraint from storyboard then set and enable remove at runtime.
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
var size = contentSize
size.height += (contentInset.top + contentInset.bottom)
size.width += (contentInset.left + contentInset.right)
return size
}
}
I am implementing a UIScrollView in a CollectionViewCell. I have a custom view which the scroll view should display, hence I am performing the following program in the CollectionViewCell. I have created everything programmatically and below is my code :
struct ShotsCollections {
let title: String?
}
class ShotsMainView: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
containerScrollView.contentSize.width = frame.width * CGFloat(shotsData.count)
shotsData = [ShotsCollections.init(title: "squad"), ShotsCollections.init(title: "genral")]
var i = 0
for data in shotsData {
let customview = ShotsMediaView(frame: CGRect(x: containerScrollView.frame.width * CGFloat(i), y: 0, width: containerScrollView.frame.width, height: containerScrollView.frame.height))
containerScrollView.addSubview(customview)
i += 1
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var shotsData = [ShotsCollections]()
var containerScrollView: UIScrollView = {
let instance = UIScrollView()
instance.isScrollEnabled = true
instance.bounces = true
instance.backgroundColor = blueColor
return instance
}()
private func setupViews() { //These are constraints by using TinyConstraints
addSubview(containerScrollView)
containerScrollView.topToSuperview()
containerScrollView.bottomToSuperview()
containerScrollView.rightToSuperview()
containerScrollView.leftToSuperview()
}
}
Now the issue is, while the scrollview is displayed, the content in it is not. I on printing the contentSize and frame of the scrollview, it displays 0. But if I check the Debug View Hierarchy, scrollview containes 2 views with specific frames.
I am not sure whats going wrongs. Any help is appreciated.
When you are adding customView in your containerScrollView, you are not setting up the constraints between customView and containerScrollView.
Add those constraints and you will be able to see your customViews given that your customView has some height. Also, when you add more view, you would need to remove the bottom constraint of the last added view and create a bottom constraint to the containerScrollView with the latest added view.
I created a sample app for your use case. I am pasting the code and the resultant screen shot below. Hope this is the functionality you are looking for. I suggest you paste this in a new project and tweak the code until you are satisfied. I have added comments to make it clear.
ViewController
import UIKit
class ViewController: UIViewController {
// Initialize dummy data array with numbers 0 to 9
var data: [Int] = Array(0..<10)
override func loadView() {
super.loadView()
// Add collection view programmatically
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.register(ShotsMainView.self, forCellWithReuseIdentifier: ShotsMainView.identifier)
self.view.addSubview(collectionView)
NSLayoutConstraint.activate([
self.view.topAnchor.constraint(equalTo: collectionView.topAnchor),
self.view.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor),
self.view.leadingAnchor.constraint(equalTo: collectionView.leadingAnchor),
self.view.trailingAnchor.constraint(equalTo: collectionView.trailingAnchor),
])
collectionView.delegate = self
collectionView.dataSource = self
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = UIColor.white
self.view.addSubview(collectionView)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = UIColor.white
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ShotsMainView.identifier, for: indexPath) as! ShotsMainView
return cell
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// The cell dimensions are set from here
return CGSize(width: collectionView.frame.size.width, height: 100.0)
}
}
ShotsMainView
This is the collection view cell
import UIKit
class ShotsMainView: UICollectionViewCell {
static var identifier = "Cell"
weak var textLabel: UILabel!
override init(frame: CGRect) {
// Initialize with zero frame
super.init(frame: frame)
// Add the scrollview and the corresponding constraints
let containerScrollView = UIScrollView(frame: .zero)
containerScrollView.isScrollEnabled = true
containerScrollView.bounces = true
containerScrollView.backgroundColor = UIColor.blue
containerScrollView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(containerScrollView)
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: containerScrollView.topAnchor),
self.bottomAnchor.constraint(equalTo: containerScrollView.bottomAnchor),
self.leadingAnchor.constraint(equalTo: containerScrollView.leadingAnchor),
self.trailingAnchor.constraint(equalTo: containerScrollView.trailingAnchor)
])
// Add the stack view that will hold the individual items that
// in each row that need to be scrolled horrizontally
let stackView = UIStackView(frame: .zero)
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
containerScrollView.addSubview(stackView)
stackView.backgroundColor = UIColor.magenta
NSLayoutConstraint.activate([
containerScrollView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor),
containerScrollView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor),
containerScrollView.topAnchor.constraint(equalTo: stackView.topAnchor),
containerScrollView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor)
])
// Add individual items (Labels in this case).
for i in 0..<10 {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(label)
label.text = "\(i)"
label.font = UIFont(name: "System", size: 20.0)
label.textColor = UIColor.white
label.backgroundColor = UIColor.purple
label.layer.masksToBounds = false
label.layer.borderColor = UIColor.white.cgColor
label.layer.borderWidth = 1.0
label.textAlignment = .center
NSLayoutConstraint.activate([
label.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 1.0, constant: 0.0),
label.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.2, constant: 0.0)
])
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Screenshot
I am having a lot of trouble getting this second custom class, which is another UICollectionView (green background) constraining to the bottom of the class above. I've tried all different sorts of constraints and constants of "0" etc. However it keeps positioning it on top of the other class. Does anyone have any ideas about what is happening?
Here is the screenshot:
class JobCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let cellId = "jobCellId"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let jobLabel: UILabel = {
let label = UILabel()
label.backgroundColor = .green
label.text = "I WANT TO"
label.textColor = UIColor.rgb(red: 149, green: 149, blue: 149)
label.font = UIFont(name: "HelveticaNeue-Medium", size: 16)
label.textAlignment = .left
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let jobsCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.red
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
func setupViews() {
backgroundColor = UIColor.clear
jobsCollectionView.dataSource = self
jobsCollectionView.delegate = self
jobsCollectionView.register(JobSingleCell.self, forCellWithReuseIdentifier: cellId)
addSubview(jobLabel)
addSubview(jobsCollectionView)
jobLabel.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
jobLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
jobLabel.widthAnchor.constraint(equalToConstant: frame.width).isActive = true
jobLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true
jobsCollectionView.topAnchor.constraint(equalTo: jobLabel.bottomAnchor, constant: 0).isActive = true
jobsCollectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
jobsCollectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
jobsCollectionView.heightAnchor.constraint(equalToConstant: frame.height).isActive = true
}
Here is the second blue cell:
class DayCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let dayCellId = "dayCellId"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let daysCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.red
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
let dayLabel: UILabel = {
let label = UILabel()
label.backgroundColor = .green
label.text = "WHEN"
label.textColor = UIColor.rgb(red: 149, green: 149, blue: 149)
label.font = UIFont(name: "HelveticaNeue-Medium", size: 16)
label.textAlignment = .left
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupViews() {
backgroundColor = UIColor.clear
addSubview(dayLabel)
dayLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
dayLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
dayLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
dayLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
I am trying to add a stack view containing a UILabel at the top and a UICollectionView underneath. I am trying to constrain the stack view so that it takes up the full view, by anchoring it to all sides. When I run the app the UILabel appears and a slice of the collection view appears. The collection view says its width and height are both zero. Any help would be appreciated, thank you.
var collectionView: UICollectionView!
var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.translatesAutoresizingMaskIntoConstraints = false
let margins = self.view.layoutMarginsGuide
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
layout.itemSize = CGSize(width: self.collectionView.frame.width / 4, height: self.collectionView.frame.width / 4)
layout.minimumInteritemSpacing = self.collectionView.frame.width / 15
layout.minimumLineSpacing = self.collectionView.frame.width / 5
collectionView.backgroundColor = UIColor.black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
titleLabel = UILabel()
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 1
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.backgroundColor = UIColor.lightGray
titleLabel.text = "Challenges"
titleLabel.textColor = UIColor.red
let stackView = UIStackView(arrangedSubviews: [titleLabel, collectionView])
stackView.backgroundColor = UIColor.white
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.spacing = 5
self.view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
//stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1.0).isActive = true
}
UPDATE:
I took my code and ran it in a new single view application and it worked as expected. Because of this I think it is worth it to mention that I am trying to incorporate this into a sprite kit game and I present the view controller by doing this:
let root = self.view?.window?.rootViewController
var viewC = SelectionCollectionViewController()
root?.present(viewC, animated: false, completion: nil)
Are there special steps I need to take because this is done with sprite kit?
I believe below screen shot is the expected output.
You might not need UIStackView , You can directly add it to self.view.
Once added to self.view, you can set up constraints. You can print the item Size in viewDidLayoutSubviews
class ViewController: UIViewController {
var collectionView: UICollectionView!
var titleLabel: UILabel!
let collectionCellIdentifier:String = "collectionCellId"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.classForCoder(), forCellWithReuseIdentifier: collectionCellIdentifier)
collectionView.backgroundColor = UIColor.black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
titleLabel = UILabel()
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 1
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.backgroundColor = UIColor.lightGray
titleLabel.text = "Challenges"
titleLabel.textColor = UIColor.red
titleLabel.translatesAutoresizingMaskIntoConstraints = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(titleLabel)
self.view.addSubview(collectionView)
setUpConstraints()
}
func setUpConstraints(){
self.view.addConstraint(NSLayoutConstraint(item: self.titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier:0, constant:50.0 ))
titleLabel.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
titleLabel.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let flowLayout = (collectionView.collectionViewLayout as! UICollectionViewFlowLayout)
flowLayout.itemSize = CGSize(width: collectionView.frame.width / 4.0 , height: collectionView.frame.width / 4.0)
flowLayout.minimumInteritemSpacing = self.collectionView.frame.width / 15.0
flowLayout.minimumLineSpacing = self.collectionView.frame.width / 5.0
}
}
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionCellIdentifier, for: indexPath)
cell.backgroundColor = UIColor.gray
return cell
}
}
I think you need to know what happen in these functions:
viewDidLoad
viewWillAppear
viewWillLayoutSubviews
viewDidLayoutSubviews
viewDidAppear
if you use autoLayout, when in viewDidLoad(), the frame is not confirmed, because the view will make an auto adjustment when in viewWillLayoutSubviews() and viewDidLayoutSubviews(), so I suggest you make these code in viewDidAppear(), and then you may see what you want!
Furthermore, if you use storyboard or nib, you need to do these in awakeFromNib()