简体   繁体   中英

swift CollectionView cell textLabel auto resize

I have watch a lot of YT tutorials for UICollectionView and UITableView, even this app that I am searching help for is made by watching and reading several tutorials, but there is one problem I can not find.

This app is made that user decide for its Username and wrote some text with that username. I have made this with Firebase, connect everything, even post is getting back to app, but problem is that is always showing only two lines of text.

This is how it look, so you can imagine better:

在此处输入图片说明

I would like that textLabel above Username expands towards down with full text written inside. Number of lines on that text Label are set to 0. I have tried several things in storyboard, with a lot of different codes and approaches, but result is always the same. Should I do this in TableView? I thought that collectionView is better approach and easier for design-wise.

Here are codes for this page VC:

import UIKit
import Firebase

class FeedViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    @IBOutlet weak var collectionView: UICollectionView!

    override func viewDidLoad() {
        super.viewDidLoad()
        loadData()
    }

    var fetchPosts = [Post]()

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    func loadData() {
        self.fetchPosts.removeAll()
        let ref = Database.database().reference()
        ref.child("Frusters").observeSingleEvent(of: .value, with: { (snapshot) in
            if let postDict = snapshot.value as? [String:AnyObject] {
                for (_,postElement) in postDict {
                    print(postElement);
                    let post = Post()
                    post.username = postElement["Username"] as? String
                    post.message = postElement["Message"] as? String
                    self.fetchPosts.append(post)
                }
            }
            self.collectionView.reloadData()

        }) { (error) in
            print(error.localizedDescription)
        }
        ref.removeAllObservers()
    }

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

        let deviceSize = UIScreen.main.bounds.size
        //let cellSize = sqrt(Double(deviceSize.width * deviceSize.height) / (Double(33)))

        let cellWidth = ((deviceSize.width / 2) - 10)
        let cellHeight = (deviceSize.height / 4)

        return CGSize(width: cellWidth , height: cellHeight)
    }*/

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return self.fetchPosts.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "messageCell", for: indexPath) as! PostCell

        cell.messageLabel.text = self.fetchPosts[indexPath.row].message
        cell.usernameLabel.text = self.fetchPosts[indexPath.row].username

        return cell
    }

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

You can see that some codes that I have testing it are now in "comment" way, because they did nothing different.

Can you please tell me what I am doing wrong? Is it something in storyboard, or did I insert wrong code, maybe did not inserted any needed code at all?

You can update label's preferredWidth or alternatively just add a height constraint with greater than or equal to value.

PS Make sure you have numberOfLines property set to 0 so the label doesn't have max number of lines which will truncate the string as well.

You can assign a dynamic height for each cell based on estimating the height that your string will take. Then if numberOfLines for your label set to 0 (infinite) or let's say 4 ~ 5 then it will work as you want.

Notice : the height constraint for your label inside each cell also should be set in a way that can extend up to a number of lines you want to display.

Estimate the height of string:

 extension String {
   func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
      let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
      let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

       return ceil(boundingBox.height)
   }
}

UICollectionView Layout delegate

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeFotItemAt indexPath: IndexPath) -> CGSize {
   let messageHeight = self.fetchPosts[indexPath.row].message.height(yourConstrainedWidth, yourFont)
   let height = height of other stuff including margins  +  messageHeight 
   return CGSize (width: view.frame.width, height: height )
}

Thank you all. You have been right. I have made it in TableView and it is much easier with same result. I have made it, so I am moving to next level of this app.

Thank you all help ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM