简体   繁体   中英

How to dynamically change the height of a UITableView Cell containing a UICollectionView cell in Swift?

Currently, I have embedded a UICollectionViewCell in a UITableViewCell within one of the sections of my UITableView . I know how to dynamically change the cell's height in another section of my UITableView because I have a UITextView in another UITableViewCell that dynamically changes the height of the cell based on how much text is in the UITextView .

The problem I have is in regards to the UITableViewCell containing the UICollectionViewCell . My UICollectionViewCell has one row of 4 images that the user can add via the camera or photo library using a UIImagePickerController .

Currently as I have it, when the 5th picture is generated, the UITableViewCell 's height remains static, but the user can scroll horizontally in the UICollectionViewCell like so:

在此处输入图片说明

My end goal is this : 在此处输入图片说明

And my storyboard:

在此处输入图片说明

Pretty self-explanatory but if there is only 4 images, the UITableViewCell remains the same as in screenshoot 1, but the cell's height will dynamically change if the UICollectionViewCell 's height changes.

I have set the UICollectionView 's scroll direction to be vertical only. Before explaining further, here's my partial code:

class TestViewController: UITableViewController, UITextFieldDelegate, UITextViewDelegate, UIImagePickerControllerDelegate
{
    override func viewDidLoad()
    {
        super.viewDidLoad()

        ....

        tableView.estimatedRowHeight = 40.0
        tableView.rowHeight = UITableViewAutomaticDimension

    }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

    {
        var cell: UITableViewCell = UITableViewCell()

        if indexPath.section == 1
        {
            cell = tableView.dequeueReusableCell(withIdentifier: "TextViewCell", for: indexPath)

            let textView: UITextView = UITextView()

            textView.isScrollEnabled = false

            textView.delegate = self
            cell.contentView.addSubview(textView)
        }
        else if indexPath.section == 4
        {
            if let imagesCell = tableView.dequeueReusableCell(withIdentifier: "ImagesCell", for: indexPath) as? CustomCollectionViewCell
            {
                if images_ARRAY.isEmpty == false
                {
                    imagesCell.images_ARRAY = images_ARRAY
                    imagesCell.awakeFromNib()
                }

                return imagesCell
            }

        }

        return cell
    }

    ....

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
    {
        if indexPath.section == 1
        {
            return UITableViewAutomaticDimension
        }
        else if indexPath.section == 4
        {
            //return 95.0
            return UITableViewAutomaticDimension
        }

        return 43.0
    }

    ....

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
    {
        if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage
        {
            if let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 4) ) as? CustomCollectionViewCell
            {
                cell.images_ARRAY.append(selectedImage)
                cell.imagesCollectionView.reloadData()
            }
        }
        picker.dismiss(animated: true, completion: nil)
    }

    ....

    func textViewDidChange(_ textView: UITextView)
    {
        ...
        // Change cell height dynamically
        tableView.beginUpdates()
        tableView.endUpdates()
    }
}

class CustomCollectionViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
{
    @IBOutlet var imagesCollectionView: UICollectionView!

    var images_ARRAY = [UIImage]()

    var images = [INSPhotoViewable]()

    override func awakeFromNib()
    {
        super.awakeFromNib()

        for image in images_ARRAY
        {
            images.append(INSPhoto(image: image, thumbnailImage: image) )
        }

        imagesCollectionView.dataSource = self
        imagesCollectionView.delegate = self
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int

    {
        return images_ARRAY.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell

    {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! ExampleCollectionViewCell

        cell.populateWithPhoto(images[(indexPath as NSIndexPath).row]

        return cell
    }

    ....

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
    {
        return UIEdgeInsetsMake(0.0, 25.0, 0.0, 25.0)
    }
}

Originally, my indexPath.section == 4 , which contains the UICollectionViewCell returned a height of 95 , but I commented that out and replaced it with returning UITableViewAutomaticDimension . I would assume that adjusted the height of the cell to fit the 5th image, but the cell remained a static height even though the UICollectionViewCell ' height changed, allowing me to scroll vertically within that static UITableViewCell height.

I know these are some questions I found very similar to my situation, but they didnt help me resolve my particular issue:

  1. Swift: Expand UITableViewCell height depending on the size of the UICollectionView inside it
  2. Auto Height of UICollectionView inside UITableViewCell
  3. UICollectionView inside a UITableViewCell — dynamic height?

With some of the answers and suggestions, I've added the following:

imagesCell.images_ARRAY = images_ARRAY
imagesCell.awakeFromNib()

// Added code
imagesCell.frame = tableView.bounds
tableView.setNeedsLayout()
tableView.layoutIfNeeded()

However, this did not have any effects. Can anyone point me in the right direction on what code I need and placed where?

Thanks!

I am using these type of cells in my code, Not performing excellent performance wise(as affecting scrolling smoothness) but will let you achieve required design.

  1. Use CollectionView inside tableViewCell with Vertical ScrollDirection and fixed width(I mean not dynamic in nature). This will put overflowing cells in vertical direction after filling horizontal direction.
  2. Take out NSLayoutConstraint from xib(if you are using that) of collectionViewHeight. We will use it in later part.
  3. set UITableViewAutomaticDimension in tableView in heightForRowAtIndexPath method.
  4. And finally set cell's collectionViewHeight while returning cell in cellForRowAtIndexPath method using constraint that we took out in step 2.

Here I am attaching some code that may will help:

UITableView Part:

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: xyzTableViewCell.self), for: indexPath) as! xyzTableViewCell
    cell.collectionViewHeight.constant = (numberOfCells/5) * cell.cellHeight
    return cell
}

UITableViewCell Part:

@IBOutlet fileprivate weak var collectionView: UICollectionView!
@IBOutlet weak var collectionViewHeight: NSLayoutConstraint

And you will need to reload that particular tableViewCell and reload collectionView inside this tableViewCell so that height function of tableView will be called and height of that tableViewCell will be refreshed, and to handle focused condition of that tableViewCell(when tableViewCell is in focus), I am saying this because if it's not in focus(or say cache, there is difference between them though) then cellForRowAtIndexPath method will be called on scrolling(when this cell is going to come in focus) then tableViewCell height will already be taken care of.

Hope this will help to achieve required functionality.

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