Unable to set width of UICollectionViewCell with A

2019-07-12 18:08发布

问题:

I have a Collection View with cells of dynamic height (based on a possibly multiline label and a textview inside), which adapts in height perfectly when I span it over multiple lines. However, when the text is just one word or it doesn't cover the entire screen width, the cell is just as wide as needed to be, resulting in cells next to each other instead of underneath each other.

Take a look at the result with different lengths of text inside the textview.

However, I want the cells to be underneath each other, think Instagram or Twitter kind of view. I obviously need to set a width constraint for the cell so it is equal to the entire width of the screen, but I can't seem to find how to do this.

I use FlowLayout with an estimatedItemSize in my AppDelegate:

let layout = UICollectionViewFlowLayout()
window?.rootViewController = UINavigationController(rootViewController: HomeController(collectionViewLayout: layout))

layout.estimatedItemSize = CGSize(width: 414, height: 150)

I also set constraints for the collectionView in viewDidLoad, so the collectionView takes on the entire width and height of the screen:

collectionView?.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
collectionView?.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
collectionView?.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
collectionView?.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true

My constraints for the label and the textview look like this, also allowing the width to take on the size required (so it's not fixed):

// vertical constraints usernameLabel & commentTextView
addConstraintsWithFormat(format: "V:|-16-[v0]-2-[v1]-16-|", views: usernameLabel, commentTextView)

// horizontal constraints usernameLabel
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", views: usernameLabel)

// horizontal constraints commentTextView
addConstraintsWithFormat(format: "H:|-16-[v0]-16-|", views: commentTextView)

All this is, according to me, essential to make this work. However, it seems to me that I have yet to set a width constraint to make this work. I have tried to add a widthAnchor on the collectionView (equal to view.widthAnchor), this didn't work:

collectionView?.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true

I have also tried to set the width in the sizeForItemAt method, but this also didn't work:

return CGSize(width: view.frame.width, height: 100)

Now, I am checking the width to see where it goes wrong, but I get the result I would need, I think:

print("collectionView width: ", collectionView?.frame.size.width)
print("collectionView height: ", collectionView?.frame.size.height)

print("screen width: ", UIScreen.main.bounds.width)
print("screen height: ", UIScreen.main.bounds.height)

Results in:

collectionView width:  Optional(414.0)
collectionView height:  Optional(736.0)
screen width:  414.0
screen height:  736.0

I am out of ideas on how to move forward. All articles or posts I have gone through related to this issue either explicitly calculate the height or use the two solutions I have mentioned above.

Any ideas on what I am doing wrong?

回答1:

Update:

I have added an extension for my HomeController according to the answer from Siju Satheesachandran:

extension HomeController {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 400, height: 100)
    }
}

Then, in the cellForItemAt method, I added a print for the width of the current cell:

print("cell width: ", cell.frame.size.width)

Which returns five times the following:

cell width:  400.0

So in my opinion, the required size is listened to, but my cell just adapts to whatever width it wants to anyways?

Another interesting update:

When I change the text of my TextView to something way too long, so it should break over multiple lines, and I run the app, the app gives this debug error infinite times while not loading and displaying a black screen:

2018-09-18 15:34:35.806688+0200 prjDynamicCells[39793:1627318] The behavior of the UICollectionViewFlowLayout is not defined because:
2018-09-18 15:34:35.807472+0200 prjDynamicCells[39793:1627318] the item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
2018-09-18 15:34:35.807572+0200 prjDynamicCells[39793:1627318] Please check the values returned by the delegate.
2018-09-18 15:34:35.807911+0200 prjDynamicCells[39793:1627318] The relevant UICollectionViewFlowLayout instance is <UICollectionViewFlowLayout: 0x7feb5ec17650>, and it is attached to <UICollectionView: 0x7feb5f841600; frame = (0 0; 414 736); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x60000044e6d0>; layer = <CALayer: 0x60000003f4a0>; contentOffset: {0, -64}; contentSize: {414, 1000}; adjustedContentInset: {64, 0, 0, 0}> collection view layout: <UICollectionViewFlowLayout: 0x7feb5ec17650>.
2018-09-18 15:34:35.808009+0200 prjDynamicCells[39793:1627318] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.


回答2:

Make sure add this protocol in app

UICollectionViewDelegate
UICollectionViewDataSource
UICollectionViewDelegateFlowLayout

Please use below method

    extension YourViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {

        func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
             return CGSize(width: screenWidth, height: screenWidth)
        }

    }