Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable width & height of UICollectionViewCell using AutoLayout with Storyboard (without XIB)

Here is an design issue in the app that uses AutoLayout, UICollectionView and UICollectionViewCell that has automatically resizable width & height depending on AutoLayout constraints and its content (some text).

It is a UITableView list like, with each cell that has it's own width & height calculated separately for each row dependant on its content. It is more like iOS Messages build in app (or WhatsUp).

It is obvious that app should make use of func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize.

Issue is that within that method, app cannot call func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell nor dequeueReusableCellWithReuseIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath!) -> AnyObject to instantiate cell, populate it with specific content and calculate its width & height. Trying to do that will result in an indefinite recursion calls or some other type of app crash (at least in iOS 8.3).

The closest way to fix this situation seems to copy definition of the cell into view hierarchy to let Auto-layout resize "cell" automatically (like cell to have the same width as parent collection view), so app can configure cell with specific content and calculate its size. This should definitely not be the only way to fix it because of duplicated resources.

All of that is connected with setting UILabel.preferredMaxLayoutWidth to some value that should be Auto-Layout controllable (not hardcoded) that could depend on screen width & height or at least setup by Auto-layout constraint definition, so app can get multiline UILabel intrinsic size calculated.

I would not like to instantiate cells from XIB file since Storyboards should be today's industry standard and I would like to have as less intervention in code.

EDIT:

The basic code that cannot be run is listed bellow. So only instantiating variable cellProbe (not used) crashes the app. Without that call, app runs smoothly.

var onceToken: dispatch_once_t = 0

class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 1
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {

        dispatch_once(&onceToken) {

            let cellProbe = collectionView.dequeueReusableCellWithReuseIdentifier("first", forIndexPath: NSIndexPath(forRow: 0, inSection: 0)) as! UICollectionViewCell
        }

        return CGSize(width: 200,height: 50)
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("first", forIndexPath: NSIndexPath(forRow: 0, inSection: 0)) as! UICollectionViewCell

        return cell
    }
}
like image 451
vedrano Avatar asked Jun 23 '15 09:06

vedrano


People also ask

What does variable width mean SPSS?

VARIABLE WIDTH specifies the column width for the display of variables in the Data Editor. It has no effect on the format of the variable or the display of the variable or values in other windows or printed results.

What is fixed and variable-width encoding?

In a fixed-width multibyte encoding scheme, each character is represented by a fixed number of bytes. The number of bytes is at least two in a multibyte encoding scheme. Variable-width multibyte encoding schemes. A variable-width encoding scheme uses one or more bytes to represent a single character.

What is fixed width encoding?

Fixed-Width Encoding. • In a fixed-width encoding scheme, each character is given a binary code with the same number of bits. – Example: Standard ASCII is a fixed width encoding scheme, where each character is encoded with 7 bits. This gives us 27 = 128 different codes for characters.

What is Pspp width?

PSPP capitalizes variable names on output the same way they were capitalized at their point of definition in the input. Type. Numeric or string. Width. (string variables only) String variables with a width of 8 characters or fewer are called short string variables.

What does the width of a string variable mean?

Nevertheless, it's good to know how when it's needed and how it's done. For string variables, width refers to how many characters a value can hold. An exception are multibyte characters as explained in SPSS Unicode Mode. Somewhat confusingly, "width" is not the width of a variable's column as displayed on screen, which is referred to as columns.

What is a variable width column chart in Excel?

Variable width column charts and histograms in Excel. In Excel, the standard column chart will display all columns with the same width at regular intervals. However, in some circumstances, it would be better for the width of each column to be different. For example, where each column represents different ranges of data.

What is variable width in SPSS?

Changing Variable Width in SPSS For string variables, width refers to how many characters a value can hold. Somewhat confusingly, "width" is not the width of a variable's column as displayed on screen, which is referred to as columns. For string variables, width should be increased when new values are desired that are longer than the current width.

What is a variable-width character set?

Most common variable-width encodings are multibyte encodings, which use varying numbers of bytes ( octets) to encode different characters. (Some authors, notably in Microsoft documentation, use the term multibyte character set, which is a misnomer, because representation size is an attribute of the encoding, not of the character set.)


3 Answers

If you are using constraints, you don't need to set a size per cell. So you should remove your delegate method func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize

Instead you need to set a size in estimatedItemSize by setting this to a value other than CGSizeZero you are telling the layout that you don't know the exact size yet. The layout will then ask each cell for it's size and it should be calculated when it's required.

let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.estimatedItemSize = someReasonableEstimatedSize()
like image 89
Ken Boreham Avatar answered Oct 07 '22 10:10

Ken Boreham


Just like when dynamically size Table View Cell height using Auto Layout you don't need call

func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

in

optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

the proper way is create a local static cell for height calculation like a class method of the custom cell

+ (CGFloat)cellHeightForContent:(id)content tableView:(UITableView *)tableView {
    static CustomCell *cell;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        cell = [tableView dequeueReusableCellWithIdentifier:[CustomCell cellIdentifier]];
    });

    Item *item = (Item *)content;
    configureBasicCell(cell, item);

    [cell setNeedsLayout];
    [cell layoutIfNeeded];
    CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    return size.height + 1.0f; // Add 1.0f for the cell separator height
}

and I seriously doubt storyboard is some industry standard. xib is the best way to create custom cell like view including tableViewCell and CollectionViewCell

like image 45
dopcn Avatar answered Oct 07 '22 10:10

dopcn


To calculate the CollectionView cell's size dynamically, just set the flow layout property to any arbitrary value:

 let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
 flowLayout.estimatedItemSize = CGSize(width: 0, height: 0)
like image 21
Bharat Bhushan Avatar answered Oct 07 '22 11:10

Bharat Bhushan