Ivan Cantarino
Ivan Cantarino

Reputation: 3246

Calculate UICollectionViewCell height base don UITextView attributed text

I have a UICollectionViewCell which has a UITextView as its subview, anchored to the cell's bounds.

What I'm trying to achieve here, is based on the UITextView attributedString , calculate the height the UITextView should have, to not to be scrollable and apply that size to the cell's height.

The problem here is that the NSAttributedString may have different font size in it and it also may have some images, which will increase its size.

How can I calculate the size, based on that content , which can have multiple inner forms (sizes, line breaks, images) ?

I use to apply the following function, but it does not work in this case, because the inner content, like font size may defer, it isn't constant:

private func estimatedHeightForText(_ text: String) -> CGFloat {
    let approximateWidthOfBioTextView = view.frame.width - 24 // paddings
    let size = CGSize(width: approximateWidthOfBioTextView, height: 1000) // height of 1000 is an arbitrary value
    let attributes = [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 12)] // attributes of the text

    // gets the estimation height based on Text
    let estimatedFrame = NSString(string: text).boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: attributes, context: nil)
    return estimatedFrame.height
}

Any hint?

Thank you very much.

Upvotes: 0

Views: 224

Answers (1)

NNikN
NNikN

Reputation: 3850

Following could be the code for a simple ViewController.

enter image description here

Where I am just loading the some dummy content in the UITextView. After which the delegate of the UITextView in the UITableViewCell is set to this ViewController.

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate,UITextViewDelegate {

    @IBOutlet var tableView:UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellId = "textCell"
        let cell = tableView.dequeueReusableCell(withIdentifier: cellId)!

        return cell

    }

    func textViewDidChange(_ textView: UITextView) {
        tableView.beginUpdates()
        tableView.endUpdates()
    }




}

There are 3 key points to achieve the auto resizing in the simple way.

1) For UITextView "Srolling Enabled" set it to "NO" .

2) Setting the UITableView Dimensions to Automatic and set some estimated height (I am using Xcode 9 , but you can set with UITableView property) enter image description here

You can also check the autolayout resizing attributes attached below.

enter image description here

3) Now when you edit the textView you can have delegate update the UITableView or reload the particular indexPath in beginUpdates and endUpdates . func textViewDidChange(_ textView: UITextView)

Upvotes: 1

Related Questions