getting the height of a label in custom cell to us

2019-08-17 04:29发布

I have a view controller that uses a custom cell called searchCell to bring content in and I am wondering how I can get the height of the label lblLeft and use it in the tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat function to return the height of the label. The code I'm using in my Main View Controller:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: 
    IndexPath) -> UITableViewCell {
    if searchMode == searching {
        let cell: MHSearchCell = tableView.dequeueReusableCell(withIdentifier: 
        MHSearchCell.ReusableIdentifier()) as! MHSearchCell

        cell.helper = helpers[indexPath.row]
        cell.delegate = self

        return cell
  }
}

Part of the code that creates the label in my MHSearchCell, the label is connected here as an IBOutlet:

lblLeft.text = ""

        if let expertiseCount = helper.expertise {

            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = 5
            paragraphStyle.lineBreakMode = .byWordWrapping
            paragraphStyle.alignment = NSTextAlignment.center
            lblLeft.numberOfLines = 0

            let finalString = expertiseCount.map({$0.name!}).joined(separator: "   \u{00B7}   ")
            let finalAttributedString = NSMutableAttributedString(string: finalString, attributes: [NSParagraphStyleAttributeName:paragraphStyle])
            lblLeft.attributedText = finalAttributedString
        }

标签: ios swift3
2条回答
【Aperson】
2楼-- · 2019-08-17 04:47

I use a custom extension to calculate the height of NSAttributedString. The "containerWidth" would be the max width of your label, which is most likely the contentView.bounds.size.width of your cell.

extension NSAttributedString {

func height(containerWidth: CGFloat) -> CGFloat {
    let rect = self.boundingRect(with: CGSize.init(width: containerWidth, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
    return ceil(rect.size.height)
}

func width(containerHeight: CGFloat) -> CGFloat {
    let rect = self.boundingRect(with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: containerHeight), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
    return ceil(rect.size.width)
}

}

One "trick" is that heightForRowAtIndexPath is called before cellForRowAtIndexPath. You need to create a placeholder cell and keep a reference to it. Then you do something like this:

// Init this once and early
var searchCellPlaceholder = SearchCell() // Use whatever the default initializer is 

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let object = data[indexPath.row]
    // Keep reusing this cell and populate it with the new object text, use the configure method in cellForRowAtIndex too.
    configureCell(cell: searchCellPlaceholder object: object)
    // Get the height of the label after the text was applied
    let height = searchCell.label.height(containerWidth: serachCell.contentView.bounds.size.width)

    return height
}

You don't want to init the placeholder cell in heightForRowAtIndexPath because it will really kill your performance to initialize an object every time that's called. That's why you initialize it from the beginning and keep reusing it.

//

If you're using auto layout, you can also look up how to have the UITableView automatically set the height of the cell for you. Which could be a better option.

查看更多
Juvenile、少年°
3楼-- · 2019-08-17 05:03

First Way either use Automatic Dimensions

1) Apply Appropriate constraints on label check the image below.

enter image description here

Make sure label Lines are set to 0 in storyboard.

Now in controller class do this-:

//MArk-: ViewDidLoad
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        yourTableView.estimatedRowHeight = 142.0 // Default cell height from storyboard

        yourTableView.rowHeight = UITableViewAutomaticDimension
    }

Table Function-:

 public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
 return UITableViewAutomaticDimension
    }

Another Way of calculating estimatedHeightForLabel-:

1) Apply same constraints to label as mentioned above

2) use boundingRect method of NSString to find exact height for cell from label -:

Table View Functions-:

extension ViewController : UITableViewDelegate,UITableViewDataSource{
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return value.count
    }


    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? testingCell
        cell?.textlabel.text = value[indexPath.row]
        return cell!
    }

    // Number of sections in table

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }// Default is 1 if not implemented

    public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat{
        let text = value[indexPath.row]
        let estimatedheight = calculateEstimatedHeight(text: text)
        return estimatedheight.height
    }

    func calculateEstimatedHeight(text:String) -> CGRect{
        let size = CGSize(width: view.frame.width, height: 1000)
        let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
        let attribute = [NSFontAttributeName:UIFont.systemFont(ofSize: 17)]
        let estimatedHeight = NSString(string: text).boundingRect(with: size, options: options, attributes: attribute, context: nil)
        return estimatedHeight
    }

Remember-:

1) Provide same font size you have for label.

2) For multiline label use option as .usesLineFragmentOrigin.

CustomCellClass-:

import UIKit

class testingCell: UITableViewCell {

    @IBOutlet weak var textlabel: UILabel!

    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
    }

}
查看更多
登录 后发表回答