UICollectionView, full-width cells, allow auto-adjust dynamic height?

Here's a pretty simple question about the current iOS development, to which I have not found a good answer.




In a (say) vertical UICollectionView ,

Is it possible to have cells of full width , but allow dynamic height for automatic detection?

(If you are familiar with iOS “dynamic height", that is, a cell has several, say, textual representations, which can be of any height, or images that can have different heights, so in the end, each cell has a completely different height.)

If so, how?

It seems to me that this is perhaps "the most important question in iOS without a really good answer."




It's for sure

The most difficult problem in all iOS :(

Mid-2019 ... I added another award - there’s still no really good solution to this ultrabasic problem. WTH, Apple? Msgstr "Make collection view elements full width."

+81
ios autolayout uicollectionview
May 25 '17 at 18:54
source share
14 answers

# 1. Solution for iOS 13

In Swift 5.1 and iOS 13, you can use Compositional Layout objects to solve your problem.

The following complete code example shows how to display a multi-line UILabel inside the full width of a UICollectionViewCell :

CollectionViewController.swift

 import UIKit class CollectionViewController: UICollectionViewController { let array = [ "Lorem ipsum.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.", "Lorem ipsum dolor sit amet.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam." ] override func viewDidLoad() { super.viewDidLoad() let size = NSCollectionLayoutSize( widthDimension: NSCollectionLayoutDimension.fractionalWidth(1), heightDimension: NSCollectionLayoutDimension.estimated(44) ) let item = NSCollectionLayoutItem(layoutSize: size) let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5) section.interGroupSpacing = 5 let layout = UICollectionViewCompositionalLayout(section: section) collectionView.collectionViewLayout = layout collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.cellIdentifier) } override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return array.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.cellIdentifier, for: indexPath) as! CollectionViewCell cell.label.text = array[indexPath.row] return cell } } 

CollectionViewCell.swift

 import UIKit class CollectionViewCell: UICollectionViewCell { static let cellIdentifier = "CellIdentifier" let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) label.numberOfLines = 0 backgroundColor = .orange contentView.addSubview(label) label.translatesAutoresizingMaskIntoConstraints = false label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } } 



# 2. Solution for iOS 12

In Swift 5 and iOS 12, you can subclass UICollectionViewFlowLayout and set its estimatedItemSize property to UICollectionViewFlowLayoutAutomaticSize (this tells the system that you want to deal with automatic resizing of UICollectionViewCell ). Then you have to redefine layoutAttributesForElements(in:) and layoutAttributesForItem(at:) to set the width of the cells. Finally, you will have to override your preferredLayoutAttributesFitting(_:) cell method and calculate their compressed fitting height.

The following complete code shows how to display a multi-line UILabel inside a full-sized UIcollectionViewCell (limited by the safe area of ​​the UICollectionView and the inserts of the UICollectionViewFlowLayout ):

CollectionViewController.swift

 import UIKit class CollectionViewController: UICollectionViewController { let items = [ "Lorem ipsum.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.", "Lorem ipsum dolor sit amet.", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam." ] let columnLayout = FlowLayout() override func viewDidLoad() { super.viewDidLoad() collectionView.alwaysBounceVertical = true collectionView.collectionViewLayout = columnLayout collectionView.contentInsetAdjustmentBehavior = .always collectionView.register(Cell.self, forCellWithReuseIdentifier: "Cell") } override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return items.count } override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell cell.label.text = items[indexPath.row] return cell } } 

FlowLayout.swift

 import UIKit class FlowLayout: UICollectionViewFlowLayout { override init() { super.init() self.minimumInteritemSpacing = 10 self.minimumLineSpacing = 10 self.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10) estimatedItemSize = UICollectionViewFlowLayout.automaticSize } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil } guard let collectionView = collectionView else { return nil } layoutAttributes.bounds.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right return layoutAttributes } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let superLayoutAttributes = super.layoutAttributesForElements(in: rect) else { return nil } guard scrollDirection == .vertical else { return superLayoutAttributes } let computedAttributes = superLayoutAttributes.compactMap { layoutAttribute in return layoutAttribute.representedElementCategory == .cell ? layoutAttributesForItem(at: layoutAttribute.indexPath) : layoutAttribute } return computedAttributes } override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { return true } } 

Cell.swift

 import UIKit class Cell: UICollectionViewCell { let label = UILabel() override init(frame: CGRect) { super.init(frame: frame) label.numberOfLines = 0 backgroundColor = .orange contentView.addSubview(label) label.translatesAutoresizingMaskIntoConstraints = false label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { layoutIfNeeded() let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes) layoutAttributes.bounds.size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow) return layoutAttributes } } 

Here are some alternative implementations for preferredLayoutAttributesFitting(_:) :

 override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { layoutIfNeeded() label.preferredMaxLayoutWidth = label.bounds.size.width layoutAttributes.bounds.size.height = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height return layoutAttributes } 
 override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { label.preferredMaxLayoutWidth = layoutAttributes.size.width - contentView.layoutMargins.left - contentView.layoutMargins.left layoutAttributes.bounds.size.height = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height return layoutAttributes } 



Expected Display:

enter image description here

+68
Jul 08 '18 at 12:11
source share

problem

You are looking for automatic height and also want to have full width. It is not possible to get both using the UICollectionViewFlowLayoutAutomaticSize .

You want to use a UICollectionView so the solution below is for you.

Decision

Step I : Calculate Expected Cell Height

1. If you have only UILabel in CollectionViewCell than set numberOfLines=0 and which calculated the expected UIlable height, pass all three parameters

 func heightForLable(text:String, font:UIFont, width:CGFloat) -> CGFloat { // pass string, font, LableWidth let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude)) label.numberOfLines = 0 label.lineBreakMode = NSLineBreakMode.byWordWrapping label.font = font label.text = text label.sizeToFit() return label.frame.height } 

2. If your CollectionViewCell contains only UIImageView and if it should be dynamic in height, then you need to get the height of UIImage (your UIImageView should have AspectRatio restrictions)

 // this will give you the height of your Image let heightInPoints = image.size.height let heightInPixels = heightInPoints * image.scale 

3. If it contains both, then their height is calculated and added together.

STEP II : Return the Size of the CollectionViewCell

1. Add the UICollectionViewDelegateFlowLayout delegate to your viewController

2. Implement the delegate method

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // This is just for example, for the scenario Step-I -> 1 let yourWidthOfLable=self.view.size.width let font = UIFont(name: "Helvetica", size: 20.0) var expectedHeight = heightForLable(array[indePath.row], font: font, width:yourWidthOfLable) return CGSize(width: view.frame.width, height: expectedHeight) } 

I hope this helps you.

+25
Jun 04 '17 at 8:12
source share

There are several ways to solve this problem.

One way - you can give the layout view of the collection view an approximate size and calculate the cell size.

Note. As mentioned in the comments below, with iOS 10, you no longer need to provide and evaluate the size in order to call the func preferredLayoutAttributesFitting(_ layoutAttributes:) cells func preferredLayoutAttributesFitting(_ layoutAttributes:) . Previously (iOS 9), you would need to provide the estimated size if you want to request prefferedLayoutAttributes cells.

(assuming you are using storyboards, and viewing the collection is connected via IB)

 override func viewDidLoad() { super.viewDidLoad() let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout layout?.estimatedItemSize = CGSize(width: 375, height: 200) // your average cell size } 

For simple cells, which will usually be enough. If the size is still incorrect, in the collection view cell you can override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes , which will give you finer control over the cell size. Note. You still need to specify the size of the schedule.

Then override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes to return the correct size.

 override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes) let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityDefaultLow) let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize) autoLayoutAttributes.frame = autoLayoutFrame return autoLayoutAttributes } 

Alternatively, you can use the calibration cell to calculate the cell size in the UICollectionViewDelegateFlowLayout .

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let width = collectionView.frame.width let size = CGSize(width: width, height: 0) // assuming your collection view cell is a nib // you may also instantiate a instance of our cell from a storyboard let sizingCell = UINib(nibName: "yourNibName", bundle: nil).instantiate(withOwner: nil, options: nil).first as! YourCollectionViewCell sizingCell.autoresizingMask = [.flexibleWidth, .flexibleHeight] sizingCell.frame.size = size sizingCell.configure(with: object[indexPath.row]) // what ever method configures your cell return sizingCell.contentView.systemLayoutSizeFitting(size, withHorizontalFittingPriority: UILayoutPriorityRequired, verticalFittingPriority: UILayoutPriorityDefaultLow) } 

While these are not ideal examples of finished products, they should start working in the right direction. I can’t say that this is the best practice, but it works for me even with rather complex cells containing several labels that may or may not be wrapped across multiple lines.

+17
May 30 '17 at 2:59 p.m.
source share

I found a fairly simple solution to this problem: inside my CollectionViewCell, I got UIView (), which is actually just a background. To get the full width, I just set the following anchors

 bgView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.size.width - 30).isActive = true // 30 is my added up left and right Inset bgView.topAnchor.constraint(equalTo: topAnchor).isActive = true bgView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true bgView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true bgView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true 

"Magic" occurs in the first line. I set widthAnchor dynamically to the width of the screen. It is also important to subtract the inserts from your CollectionView. Otherwise, the cell will not appear. If you do not want to have such a background look, just make it invisible.

FlowLayout uses the following settings

 layout.itemSize = UICollectionViewFlowLayoutAutomaticSize layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize 

The result is a cell with full width and dynamic height.

enter image description here

+14
Feb 08 '18 at 8:58
source share

You must add a width constraint to CollectionViewCell

 class SelfSizingCell: UICollectionViewCell { override func awakeFromNib() { super.awakeFromNib() contentView.translatesAutoresizingMaskIntoConstraints = false contentView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width).isActive = true } } 
+6
Apr 14 '18 at 21:34
source share

Personally, I have found better ways to have a UICollectionView where AutoLayout determines the size, while each cell can have a different size - this is to implement the UICollectionViewDelegateFlowLayout sizeForItemAtIndexPath function using the actual cell to measure the size.

I talked about this in one of my blog posts.

Hope this one helps you achieve what you want. I'm not 100% sure, but I believe that unlike UITableView, where you can have fully automatic cell heights using AutoLayout in conjunction with

 tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = 44 

UICollectionView does not have such a way to allow AutoLayout to determine the size, because the UICollectionViewCell does not necessarily fill the entire width of the screen.

But here's the question for you : if you need cells of the full width of the screen, why would you even use a UICollectionView on top of the good old UITableView that comes with autosize cells?

+3
Jun 03 '17 at 17:12
source share

According to my comment on Eric's answer, my solution is very similar to it, but I had to add a constraint to my preferred size for ... to limit a fixed size.

  override func systemLayoutSizeFitting( _ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { width.constant = targetSize.width let size = contentView.systemLayoutSizeFitting( CGSize(width: targetSize.width, height: 1), withHorizontalFittingPriority: .required, verticalFittingPriority: verticalFittingPriority) print("\(#function) \(#line) \(targetSize) -> \(size)") return size } 

There are several duplicates in this question, I answered them in detail here and provided an example of a working application.

+3
Dec 15 '17 at 4:09 on
source share
  1. Set the estimatedItemSize size of your stream layout:

     collectionViewLayout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize 
  2. Define the width limit in the cell and set it equal to the width of the superview:

     class CollectionViewCell: UICollectionViewCell { private var widthConstraint: NSLayoutConstraint? ... override init(frame: CGRect) { ... // Create width constraint to set it later. widthConstraint = contentView.widthAnchor.constraint(equalToConstant: 0) } override func updateConstraints() { // Set width constraint to superview width. widthConstraint?.constant = superview?.bounds.width ?? 0 widthConstraint?.isActive = true super.updateConstraints() } ... } 

Full example

Tested on iOS 11.

+3
Jul 02 '18 at 9:30
source share

Not sure if this qualifies as a “really good answer,” but this is what I use to achieve this. My stream structure is horizontal, and I'm trying to adjust the width with autostart, so it looks like your situation.

 extension PhotoAlbumVC: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // My height is static, but it could use the screen size if you wanted return CGSize(width: collectionView.frame.width - sectionInsets.left - sectionInsets.right, height: 60) } } 

Then in the view controller, where the autodetection constraint changes, I run NSNotification.

 NotificationCenter.default.post(name: NSNotification.Name("constraintMoved"), object: self, userInfo: nil) 

In my subclass of UICollectionView, I listen to this notification:

 // viewDidLoad NotificationCenter.default.addObserver(self, selector: #selector(handleConstraintNotification(notification:)), name: NSNotification.Name("constraintMoved"), object: nil) 

and invalid layout:

 func handleConstraintNotification(notification: Notification) { self.collectionView?.collectionViewLayout.invalidateLayout() } 

This calls sizeForItemAt again, using the new collection view. In your case, it should be able to update the data, given the new restrictions available in the layout.

+2
May 31 '17 at 20:57
source share

Starting with iOS 10, for this we have a new API for the stream layout.

All you have to do is set your flowLayout.estimatedItemSize to a new constant, UICollectionViewFlowLayoutAutomaticSize .

Source

+2
Jun 03 '17 at 17:25
source share

On your viewDidLayoutSubviews set the estimatedItemSize to full width (the layout refers to the UICollectionViewFlowLayout object):

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { return CGSize(width: collectionView.bounds.size.width, height: 120) } 

In your cell, make sure your constraints apply to both the top and bottom of the cell (the following code uses mapping to make it easier to set limits, but you can do this with NSLayoutConstraint or IB if you want):

 constrain(self, nameLabel, valueLabel) { view, name, value in name.top == view.top + 10 name.left == view.left name.bottom == view.bottom - 10 value.right == view.right value.centerY == view.centerY } 

Fought, you will now automatically increase the height!

+1
Sep 22 '17 at 20:58
source share

AT WORK!!! Tested on iOS: 12.1

I have a very simple solution that just works without breaking restrictions.

enter image description here

My ViewControllerClass

 class ViewController: UIViewController { @IBOutlet weak var collectionView: UICollectionView! let cellId = "CustomCell" var source = ["nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,","nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,","nomu", "when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. ", "t is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by", "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia,"] override func viewDidLoad() { super.viewDidLoad() self.collectionView.delegate = self self.collectionView.dataSource = self self.collectionView.register(UINib.init(nibName: cellId, bundle: nil), forCellWithReuseIdentifier: cellId) if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize } } } extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return self.source.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as? CustomCell else { return UICollectionViewCell() } cell.setData(data: source[indexPath.item]) return cell } } 

CustomCell Class:

 class CustomCell: UICollectionViewCell { @IBOutlet weak var label: UILabel! @IBOutlet weak var widthConstraint: NSLayoutConstraint! override func awakeFromNib() { super.awakeFromNib() self.widthConstraint.constant = UIScreen.main.bounds.width } func setData(data: String) { self.label.text = data } override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { return contentView.systemLayoutSizeFitting(CGSize(width: self.bounds.size.width, height: 1)) } } 

systemLayoutSizeFitting Customcell. .

+1
19 . '19 16:07
source share

, iPhone'.

  class CustomLayoutFlow: UICollectionViewFlowLayout { override init() { super.init() minimumInteritemSpacing = 1 ; minimumLineSpacing = 1 ; scrollDirection = .horizontal } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) minimumInteritemSpacing = 1 ; minimumLineSpacing = 1 ; scrollDirection = .horizontal } override var itemSize: CGSize { set { } get { let width = (self.collectionView?.frame.width)! let height = (self.collectionView?.frame.height)! return CGSize(width: width, height: height) } } } class TextCollectionViewCell: UICollectionViewCell { @IBOutlet weak var textView: UITextView! override func prepareForReuse() { super.prepareForReuse() } } class IntroViewController: UIViewController, UITextViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, UINavigationControllerDelegate { @IBOutlet weak var collectionViewTopDistanceConstraint: NSLayoutConstraint! @IBOutlet weak var collectionViewTopDistanceConstraint: NSLayoutConstraint! @IBOutlet weak var collectionView: UICollectionView! var collectionViewLayout: CustomLayoutFlow! override func viewDidLoad() { super.viewDidLoad() self.collectionViewLayout = CustomLayoutFlow() self.collectionView.collectionViewLayout = self.collectionViewLayout } override func viewWillLayoutSubviews() { self.collectionViewTopDistanceConstraint.constant = UIScreen.main.bounds.height > 736 ? 94 : 70 self.view.layoutIfNeeded() } } 
0
05 . '17 23:40
source share

UICollectionViewDelegateFlowLayout . :

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

, .

collectionViewController tableViewController.

, , , , .

-6
28 '17 21:44
source share



All Articles