Is it possible to have differing heights in a UITableView Cell when I use several different ways of displaying the cell?

后端 未结 11 1262
一整个雨季
一整个雨季 2020-12-21 19:25

I\'ve spent several days trying to figure this out, but there doesn\'t seem to be a solution. I have a very basic UITableView cell with two labels in it. One of them will be

相关标签:
11条回答
  • 2020-12-21 20:13

    As of iOS 9.1 UIStackView doesn't implement intrinsicContentSize: so the table view can't calculate the height of each cell, thus they are displayed at the estimated height instead.

    So, ideally you would simplify your code to mean you don't use a stack view and you don't keep adding and removing (and creating and destroying) views all the time. The root of the solution is to not use a stack view though.

    You can continue to use a stack view if you want, but you'll need to create a subclass and implement intrinsicContentSize:. Your reason for using the stack view shouldn't be required though as you can configure the constraints to match first baselines.

    0 讨论(0)
  • 2020-12-21 20:14
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    
    
        NSString *firstLable = firstLable.text;
        NSString *secondLable = SecondLable.text;
    
    
    
        CGSize constraint = CGSizeMake(cell.frame.size.width/2, 20000.0f);
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
        CGRect firstLableRect = [firstLable boundingRectWithSize:constraint
                           options:NSStringDrawingUsesLineFragmentOrigin
                           attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],      
                            NSParagraphStyleAttributeName: paragraphStyle.copy} context:nil];
    
    
        CGRect secondLableRect = [secondLable boundingRectWithSize:constraint
                                  options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],                                       NSParagraphStyleAttributeName: paragraphStyle.copy}context:nil];
    
    
        float max = MAX(firstLableRect.size.height, secondLableRect.size.height) + 20;
    
    
        //20 for spacing 10 pc above and 10 pc below 
    
    
        return max ;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *cellIdentifier=@"cellIdentifier";
        UITableViewCell *cell =  [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
        if (!cell)
        {
            cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
        }
        cell.selectionStyle =UITableViewCellSelectionStyleNone;
    
    
    
        NSString *lable1 = @"first label text";
        NSString *lable2 = @"second lable text";
    
        CGSize constraint = CGSizeMake(cell.frame.size.width/2-10, 20000.0f);
        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
        CGRect firstLableRect = [lable1 boundingRectWithSize:constraint
                                 options:NSStringDrawingUsesLineFragmentOrigin
                                 attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],
                                 NSParagraphStyleAttributeName: paragraphStyle.copy} context:nil];
    
    
        CGRect secondLableRect = [lable2 boundingRectWithSize:constraint
                                  options:NSStringDrawingUsesLineFragmentOrigin
                                  attributes:@{NSFontAttributeName:[UIFont fontWithName:@"Your App Font" size:16.0f],                                       NSParagraphStyleAttributeName: paragraphStyle.copy}context:nil];
    
    
    
        UILabel *firstLable = [[UILabel alloc]initWithFrame:CGRectMake(5,10,constraint.width,firstLableRect.size.height)];
        [firstLable setLineBreakMode:NSLineBreakByWordWrapping];
        firstLable.minimumScaleFactor = 15.0f;
        [firstLable setNumberOfLines:0];
        firstLable.textAlignment = NSTextAlignmentLeft;
        [firstLable setFont:[UIFont fontWithName:@"your App font" size:16.0f]];
        [cell.contentView addSubview:firstLable];
    
    
        UILabel *secondLable = [[UILabel alloc]initWithFrame:CGRectMake(cell.frame.size.width/                       2+5,10,constraint.width,secondLableRect.size.height)];
        [secondLable setLineBreakMode:NSLineBreakByWordWrapping];
        secondLable.minimumScaleFactor = 15.0f;
        [secondLable setNumberOfLines:0];
        secondLable.textAlignment = NSTextAlignmentLeft;
        [secondLable setFont:[UIFont fontWithName:@"your App font" size:16.0f]];
    
        [cell.contentView addSubview:secondLable];
    
        return cell;
    }
    
    0 讨论(0)
  • 2020-12-21 20:15

    The height of a table view cell is decided by the table based on the rowHeight property, or on the return value of optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat from the table view delegate.

    The height that may be set by the programmer for the UITableViewCell through its frame property is ignored!

    Hence you need to figure out the desired height of each cell programatically. Then you need to implement optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat from the table view delegate for each of the cells.

    If the size of a cell changes while the table view is displayed, you need to either:

    • reload the table with reloadData() from UITableView, or
    • update the cell with func reloadRowsAtIndexPaths(_ indexPaths: [NSIndexPath], withRowAnimation animation: UITableViewRowAnimation) from UITableView.

    Edit

    Actually since you are using constraints in you view it should work without using ``.

    Try to replace the code in if categories[parent] == "words" { .. } with:

            cell = tableView.dequeueReusableCellWithIdentifier(childWordsCellIdentifier, forIndexPath: indexPath) as UITableViewCell
    
            // Reset content
            for subview in cell.contentView.subviews {
                subview.removeFromSuperview()
            }
            cell.prepareForReuse()
    
    
            let words                   = self.page.valueForKey("words")!.allObjects as! [Word]
            let wordsInOrder            = words.sort({Int($0.order!) < Int($1.order!) })
            let word                    = wordsInOrder[indexPath.row - 1]
    
    
            let wordLabel               = UILabel(frame: CGRectZero)
            wordLabel.text              = word.valueForKey("sanskrit") as? String
            wordLabel.font              = UIFont(name: "EuphemiaUCAS-Bold", size: 16)
            wordLabel.numberOfLines     = 0
            wordLabel.translatesAutoresizingMaskIntoConstraints = false
            wordLabel.layer.borderColor = UIColor.greenColor().CGColor
            wordLabel.layer.borderWidth = 1.0
    
            let englishWordLabel           = UILabel(frame: CGRectZero)
            englishWordLabel.text          = "Foobar don't want to play my game with my anymore."
            englishWordLabel.font          = UIFont(name: "STHeitiTC-Light", size: 16)
            englishWordLabel.numberOfLines = 0
    
            let stackView = UIStackView()
            stackView.axis = .Horizontal
            stackView.distribution = .FillProportionally
            stackView.alignment = .Fill  // EDIT
            stackView.spacing = 15
            stackView.layoutMargins = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
            stackView.layoutMarginsRelativeArrangement = true
    
            stackView.addArrangedSubview(wordLabel)
            stackView.addArrangedSubview(englishWordLabel)
    
            stackView.translatesAutoresizingMaskIntoConstraints = false
    
            cell.contentView.addSubview(stackView)
            cell.contentView.leadingAnchor.constraintEqualToAnchor(stackView.leadingAnchor).active = true
            cell.contentView.topAnchor.constraintEqualToAnchor(stackView.topAnchor).active = true
            cell.contentView.trailingAnchor.constraintEqualToAnchor(stackView.trailingAnchor).active = true
            cell.contentView.bottomAnchor.constraintEqualToAnchor(stackView.bottomAnchor).active = true
    
            cell.contentView.layoutIfNeeded()
    

    Also I would have used two different cells classes for this task rather than removing the views in the contentView.

    Please let me know how it goes!

    0 讨论(0)
  • 2020-12-21 20:16

    First of all, unless you need a UIStackView for some other purpose that you're not mentioning in your question, don't use them. Multi-line labels and dynamic height cells work well without them (don't needlessly complicate the code if they are not necessary).

    There are no bugs in iOS that stop this from working, that I'm aware of. Dynamically sized cells work great with Auto Layout, all you need to do is set the correct constraints in the cells and set the rowHeight and estimatedRowHeight properties of the table view.

    The most likely reason this is not working for you is that you have not put all the needed constraints in your cell. The needed constraints are:

    1. A top constraint from your cell content (i.e. your multi-line label) to the top of the cell content view
    2. A leading constraint from your single-line label to the left of the cell
    3. A trailing constraint from your multi-line label to the right of your cell
    4. A bottom constraint from the bottom of your multi-line label to the bottom of your cell

    I think you're missing point 4.

    Edit

    According to your comments, you're using a UIStackView so as to align the top baselines between the single and the multi-line labels. By this, I understand you want your labels to align like this:

    To get this behaviour, you don't need a UIStackView. Just give the labels constraints to allow the multi-line label to define the cell height. The following image shows the top baselines aligned between the two labels (i.e. the first lines of each label are aligned).

    Notice how the left label only needs a leading and top constraint, while the right label needs a top, trailing and bottom, because it defines cell height.

    In summary, dynamic table view cells require three things:

    1. tableView.rowHeight = UITableViewAutomaticDimension
    2. tableView.estimatedRowHeight = 100
    3. The cell content must have all four constraints (leading, trailing, top and bottom) to define cell height.
    0 讨论(0)
  • 2020-12-21 20:18

    This is very easy.lets go step by step.

    1. set the estimatedRowHeight of table view.It makes easy and fast to load the cell.

    2.set the rowHeight property of tableview as UITableViewAutomaticDimension.and don't use heightForRowAtIndexPath.

    3.put the all top bottom leading and trailing constraint on both Label.its important.

    Lets rock and roll no need to use stackView

    0 讨论(0)
提交回复
热议问题