【问题标题】:Dynamic Height Issue for Custom UITableViewCell自定义 UITableViewCell 的动态高度问题
【发布时间】:2020-12-16 16:22:26
【问题描述】:

我有一个自定义UITableViewCell,其中包含一个UICollectionView

我在其XIB 文件的每一侧都固定了UICollectionView

在我的一些单元格中,内容可能会向下移动,但根据我当前的动态高度设置,我只能看到顶部。我正在将图像添加到我的UICollectionView,所以在一个单元格中可能有 20 个,而另一个可能只有 5 个。现在每一行都有相同的高度,而有些应该不同。

请注意,单元格中的UICollectionView 不会滚动。

这是我在视图控制器中尝试的:

// Here is where I am getting the arr data, which is the folders
// that contains images.
func getDataForSections() {
    
    let storageReference = Storage.storage()
    let ref = storageReference.reference().child("abc/xyz/")
    
    ref.listAll { (result, error) in
        
        if let error = error {
            // ...
        }
                    
        for prefix in result.prefixes {
            self.arr.append(prefix)
        }
        
        self.myTableView.reloadData()
    }
}

func numberOfSections(in tableView: UITableView) -> Int {
    
    return arr.count
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
    let data = arr[indexPath.section]
    let cell = tableView.dequeueReusableCell(withIdentifier: "collectionCell", for: indexPath) as! collectionCell
    cell.getImagesFromData(data: data)
    cell.frame = tableView.bounds
    cell.layoutIfNeeded()
    cell.collectionView.reloadData()
    cell.collectionView.heightAnchor.constraint(equalToConstant: cell.collectionView.collectionViewLayout.collectionViewContentSize.height).isActive = true
    cell.layoutIfNeeded()
    return cell
}

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {

    // How Do I get the Custom size here? Or in heightForRowAt?
    return 500.0
}

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

/**
 @param numberOfCellsInCollectionView the number of cells of your current collectioview
 */
func calculateHeight(numberOfCellsInCollectionView: Int) -> CGFloat {
    let imageHeight: CGFloat = 40.0
    let spaceBetweenRows: CGFloat = 20.0 /*Change as you please based on the space you put between your cells (if any) */
    let rows: CGFloat = CGFloat(calculateRows(numberOfCellsInCollectionView: numberOfCellsInCollectionView))
    
    /**
     1) (rows*imageHeight) calculate the total space occupied by the pictures
     2) (rows+2) assuming you want to put a little space between the top and the bottom of the collectionview i used +2. If you don't want to remove the +2
     3) ((rows+2)*spaceBetweenRows) total space occupied by the spaces.
     **/
    let height = (rows*imageHeight)+((rows+2)*spaceBetweenRows)
   
    return height
    
}

//Calculate the rows
func calculateRows(numberOfCellsInCollectionView: Int) -> Int {
    let result = numberOfCellsInCollectionView/6 //Dividing the number of cells for the cells for row
    let rest = numberOfCellsInCollectionView%6 //Calculating the module
    
    if rest == 0 {
        //If the rest is 0 (ie: you divide 18/6), then you get the result of the division (18/6 = 3)
        return result
    } else {
        //If the rest is > 0 (ie: you divide 17/6), then you get the result of the division + 1 (17/6 = 3+1 = 4) so there's space for the last item
        return result+1
    }
}

这是我在具有集合视图的自定义单元格中尝试的内容:

func getImagesFromData(prefix: String) {
    
    let storageReference = Storage.storage()
    let ref = storageReference.reference().child("abc/xyz/\(prefix)")
    
    ref.listAll { (result, error) in
                    
        if let error = error {
            // ...
        }
        
        self.folderImages.removeAll()
                    
        for item in result.items {
            
            if !self.folderImages.contains(item) {
                self.folderImages.append(item)
            }
        }

       // Here is where I need to store (or retain) the count 
       // for each section and then calculate the height or pass
       // this data back to the View Controller. 
       // But with Firebase I am not sure how to return this or 
       // use a completion.
                                            
        // reload collection data
        self.myCollectionView.reloadData()
    }
}

extension customCollectionCell: UICollectionViewDataSource, UICollectionViewDelegate {

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

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "imageCell", for: indexPath) as! imageCell
        let theImage = folderImages[indexPath.item]
        cell.imageView.sd_setImage(with: theImage, placeholderImage: UIImage(named: "blah")) { (image, error, cacheType, ref) in
            if error != nil {
                cell.imageView.image = UIImage(named: "blah")
            }
        }
        return cell
    }
}

另一个例子:

这里不是使用UITableViewUICollectionViewCell,而是使用UICollectionViewUICollectionViewCell...

我还使用UIViewController 中单元格内的方法的变体来获取计数。

在这个例子中,我可以看到返回之前的值。我只需要知道如何在返回值中获取该值作为高度。

这是我尝试过的:

func collectionView(_ collectionView: UICollectionView,
                  layout collectionViewLayout: UICollectionViewLayout,
                  sizeForItemAt indexPath: IndexPath) -> CGSize {

    let prefix = arr[indexPath.section]

    getImageCountFromPrefix(prefix: prefix.name, completion: { (count, success) in
        if success {
            self.h = self.calculateHeight(numberOfCellsInCollectionView: count)
            // self.h has a value!!! How do I get it in the return?
        }
    })

    return CGSize(width: collectionView.bounds.size.width, height: self.h)
}

【问题讨论】:

    标签: ios swift uitableview uicollectionview


    【解决方案1】:

    创建一个函数来确定单元格内图片的高度,然后只使用heightForRowAtIndexPath 函数,如下所示:

     private func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat{
           /* Here I'll just assume the height of the picture is 30. You'll have to put here your function and return the dimension. */
            return 30.0
        }
    

    请注意,您可能希望在返回值中添加一个常量值,以使单元格的外观更加清晰。我一般加70.0

    哦,我不知道图像,但是当您处理文本时,您还必须在 cellForRowAt 中调用这些。

    cell.textLabel?.sizeToFit()
    cell.textLabel?.numberOfLines = 0
    

    这里是如何计算你的收藏视图的高度

    /**
     @param numberOfCellsInCollectionView the number of cells of your current collectioview
     */
    func calculateHeight(numberOfCellsInCollectionView: Int) -> CGFloat{
        let imageHeight: CGFloat = 40.0
        let spaceBetweenRows: CGFloat = 5.0 /*Change as you please based on the space you put between your cells (if any) */
        let rows: CGFloat = CGFloat(calculateRows(numberOfCellsInCollectionView: numberOfCellsInCollectionView))
        
        /**
         1) (rows*imageHeight) calculate the total space occupied by the pictures
         2) (rows+2) assuming you want to put a little space between the top and the bottom of the collectionview i used +2. If you don't want to remove the +2
         3) ((rows+2)*spaceBetweenRows) total space occupied by the spaces.
         **/
        let height = (rows*imageHeight)+((rows+2)*spaceBetweenRows)
       
        return height
        
    }
    
    //Calculate the rows
    func calculateRows(numberOfCellsInCollectionView: Int) -> Int{
        let result = numberOfCellsInCollectionView/6 //Dividing the number of cells for the cells for row
        let rest = numberOfCellsInCollectionView%6 //Calculating the module
        
        if rest == 0 {
            //If the rest is 0 (ie: you divide 18/6), then you get the result of the division (18/6 = 3)
            return result
        } else {
            //If the rest is > 0 (ie: you divide 17/6), then you get the result of the division + 1 (17/6 = 3+1 = 4) so there's space for the last item
            return result+1
        }
    }
    

    【讨论】:

    • 图片为 40x40。 UICollectionView 已设置好,因此将连续出现 6 个。
    • 对,我的错,我忽略了部分问题。但是,您应该计算集合视图的高度并将其返回到 heightForRowAtIndexPath 中。您还应该调用 cell.sizeToFit() 但我不知道 numberOfLines 的等价物。如果您需要更多帮助,请告诉我
    • 关于计算 UICollectionView 高度的最佳方法有什么建议吗?所以现在我得到的值看起来是我需要的,但这是在其他所有内容都加载之后。所以不确定如何正确返回该值。
    • 感谢您对此提供的帮助。所以,虽然这些确实返回了我需要的值,但我仍然不知道应该在哪里调用它们。在我可以将值传递给它之前,我的所有设置都已加载。我正在使用 Firebase。所以我想知道是不是因为这个。我似乎无法找到如何从他们的方法中返回值,并且我可以在任何调整大小的方法中使用它们。
    • 在heightForRowAtIndexPath中调用计算高度,使其成为返回值。如果在加载视图之前无法访问数据,这不是问题。您可以创建辅助变量,您将在加载所需数据后为其赋值。使用这些辅助变量代替您丢失的数据。
    猜你喜欢
    • 2014-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多