I am trying to modify the size of the cells that the UICollectionview contains. I believe that the sizeForItemAtIndexPath should do the trick. Yet nothing is happening.
I have looked into similar questions, they have advised doing the same thing. I am sort of suspicious of my inheritance.
The problem is that the cells remain in the same size regardless of the value they were fed in.
class HikeViewController: UIViewController {
var test: Int?
#IBOutlet weak var options: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = false
print(test!)
options.dataSource = self
options.delegate = self
}
}
extension HikeViewController: UICollectionViewDelegate, UICollectionViewDataSource {
//collectionCell
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionCell", for: indexPath as IndexPath)
cell.backgroundColor = UIColor.green
return cell
}
func collectionView(collectionView : UICollectionView,layout collectionViewLayout:UICollectionViewLayout,sizeForItemAtIndexPath indexPath:NSIndexPath) -> CGSize
{
return CGSize(width: 400, height: 500)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.row)
}
}
And when I conform to UICollectionViewDelegateFlowLayoutthe app termainates where I set the followings:
options.dataSource = self
options.delegate = self
And the error is:
Could not cast value of type 'HikingClub.HikeViewController' (0x108e1f948) to 'UICollectionViewDataSource' (0x10e723ff0).
It's worth adding that I have made sure of the connection between HikeViewController and the storyboard.
extension HikeViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {
}
It should be something like this
Make your extension a subclass of UICollectionViewDelegateFlowLayout
Use the following function
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// code
}
You need to specify that you implement the protocol UICollectionViewDelegateFlowLayout in your class declaration.
extension HikeViewController: UICollectionViewDelegateFlowLayout {}
also you have are not calling the delegate method, just defining a new one.
check the first parameter (collectionView -> _ collectionView)
func collectionView(_ collectionView : UICollectionView,layout collectionViewLayout:UICollec
Related
I have trying to make a program that will display the image of crystals. After writing the code and formatting the StoryBoard, when I run the app the images are tiny and there are no labels displayed. I have constraints.
Here is the code:
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
let imageArray = [UIImage(named: "1"),UIImage(named: "2"),UIImage(named: "3")]
let nameArray = ["Rose Quartz", "Clear Quartz", "Clear Quartz 2"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainCollectionViewCell", for: indexPath) as! MainCollectionViewCell
cell.crystalPhotoImageView.image = imageArray[indexPath.row]
cell.crystalNameLabel.text! = nameArray[indexPath.row]
return cell
}
}
you need to implement to confirm the class has UICollectionViewDelegateFlowLayout and you need to implement this functionn
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return cellSize
}
I am having UICollectionView inside a UITableViewCell and its delegate and datasource are declared there in table cell class. It works fine for first time loading but later on changes it's size when I scroll collection.
I noticed sizeForItemAt is called only while loading but not while setting the cells during scroll.
class HomeCell: UITableViewCell {
#IBOutlet weak var collHomeSongs: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func setCollection() {
collHomeSongs.delegate = self
collHomeSongs.dataSource = self
}
}
extension HomeCell: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize.init(width: 120, height: 180)
}
}
I just got it's solution this problem arises in Xcode 11+, and solution to it is set collection view automatic size to "None".
Refer: Why on Xcode 11, UICollectionViewCell changes size as soon as you scroll (I already set size in sizeForItem AtIndexPath:)?
I have been trying to implement a vertical collection view inside a horizontal collection view. I have succeeded in my venture up to great extent. But when the device is rotated from portrait to landscape mode, the vertical collection view cells do not resize. Although the cells resize properly when the device enters from landscape to portrait mode. Even the horizontal collection view cells resize properly as I have invalidated the flow layout inside the viewWillTransitionToSize function. I have implemented the same function (with other functions like numberOfItemsAtIndexPath, cellForItemAt, sizeForItemAt, , etc.) for vertical collection view too (inside a class "HorizontalCollectionViewCell" in a separate CocoaTouch file). But all in vein. All the view and subviews (including the two collection views) have been created using storyboard (not code). I have been searching for the solution for last 1 week , but haven't succeeded yet. Kindly help me find a proper solution for this problem.
Here is the code inside ViewController file:-
import UIKit
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var horizontalView: UIView! // Container View for horizontal Collection View.
#IBOutlet weak var horizontalCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
horizontalCollectionView.delegate = self
horizontalCollectionView.dataSource = self
menuBarCollectionView.delegate = self
menuBarCollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == menuBarCollectionView {
let cell = menuBarCollectionView.dequeueReusableCell(withReuseIdentifier: "menuButtonsCell", for: indexPath) as! MenuBarCollectionViewCell
cell.menuButtonsLabel.text = menuButtonsName[indexPath.row]
return cell
}
let cell = horizontalCollectionView.dequeueReusableCell(withReuseIdentifier: "horizontalCell", for: indexPath) as! HorizontalCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView == menuBarCollectionView {
let menuButtonWidthFactor = self.menuBarView.frame.width - 1
return CGSize(width: menuButtonWidthFactor / 3, height: 35)
}
return CGSize(width: horizontalView.frame.width, height: horizontalView.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
if collectionView == menuBarCollectionView {
return 0.5
}
return 0
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
menuBarCollectionView.collectionViewLayout.invalidateLayout()
horizontalCollectionView.collectionViewLayout.invalidateLayout()
}
}
Here is the code inside subclass HorizontalCollectionViewCell file:-
import UIKit
class HorizontalCollectionViewCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var verticalCollectionView: UICollectionView! {
didSet {
self.verticalCollectionView.delegate = self
self.verticalCollectionView.dataSource = self
}
}
#IBOutlet weak var verticalView: UIView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = verticalCollectionView.dequeueReusableCell(withReuseIdentifier: "verticalCell", for: indexPath)
cell.backgroundColor = UIColor.red
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.verticalView.frame.width, height: 100)
}
func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
verticalCollectionView.collectionViewLayout.invalidateLayout()
}
}
I got two questions.
I am wondering why my collection view automatically load data without calling imageCollectionView.reloadData().
Solved. See comment
Why func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize is not called? I didn't see the print("collectionViewLayout called") I am trying to modify the cell's size so the cell's height equals to the collection view height
Solved. See comment
Here is the codes
class ProductInternalDetailVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
var selectedProduct: Product?
#IBOutlet weak var imageCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
imageCollectionView.delegate = self
imageCollectionView.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath) as! ProductInternalDetailCVC
if indexPath.row == 0 {
cell.productImage.image = selectedProduct!.image1
} else {
cell.productImage.image = selectedProduct!.image2
}
cell.productImage.frame = CGRect(x: 1, y: 1, width: cell.frame.size.width-2, height: cell.frame.size.height-2)
return cell
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
//return CGSize(width: collectionView.frame.size.height-1, height: collectionView.frame.size.height-1)
print("collectionViewLayout called")
return CGSize(width: 10, height: 10)
}
}
class ProductInternalDetailCVC: UICollectionViewCell {
#IBOutlet weak var productImage: UIImageView!
}
Thanks for the help.
Question 2: The function signature has changed a bit. Change the function signature with this:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
...
}
And don't forget to implement the UICollectionViewDelegateFlowLayout protocol.
Question 1:
When entering the ViewController your collectionView loads the datasource of the collectionView automatically if this is your question.for example, make changes on datasource without changing the view (means without calling viewDidLoad method) you will not see the changes until you call imageCollectionView.reloadData().
I am trying to create collectionView inside another collectionViewCell. I can get the cell of outer collectionView however, compiler is not executing inner cell. How can I get both the cells?
P.S I am new at this.
CollectionViewController Class:
class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout{
#IBOutlet var collectionView1: UICollectionView!
var coll2 = CollectionViewCell()
override func viewDidLoad() {
super.viewDidLoad()
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 150)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)as! CollectionViewCell
cell.backgroundColor = UIColor.black
return cell
}
}
CollectionViewCell CLass:
class CollectionViewCell: UICollectionViewCell {
#IBOutlet var collectionView2: UICollectionView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView2.frame.width, height: 150)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath)as! CollectionViewCell2
cell1.backgroundColor = UIColor.red
return cell1
}
enter image description here
}
set the delegates and data source of inner collection view to the first collection view cell.
override func awakeFromNib()
{
super.awakeFromNib()
// Initialization code
self.collectionView2?.delegate = self
self.collectionView2?.dataSource = self
}
The reason why CollectionViewCell is not setting up the collectionView2 is because you didn't set delegate and dataSource properties of collectionView2 to the instance of CollectionViewCell.
I have created a method called setupViews in CollectionViewCell so that it can be called when you are dequeuing a CollectionViewCell in CollectionViewController so that the delegate and dataSource are being setup properly.
class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 150)
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)as! CollectionViewCell
cell.backgroundColor = UIColor.black
cell.setupViews() // added this call
return cell
}
}
class CollectionViewCell: UICollectionViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
#IBOutlet weak var collectionView2: UICollectionView!
// added this method
func setupViews() {
collectionView2.delegate = self
collectionView2.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView2.frame.width, height: 150)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell1 = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath)
cell1.backgroundColor = UIColor.red
return cell1
}
}