由于完成处理程序,单元格高度未正确计算

Posted

技术标签:

【中文标题】由于完成处理程序,单元格高度未正确计算【英文标题】:Cell height not being calculated properly because of Completion Handler 【发布时间】:2016-03-07 14:59:17 【问题描述】:

我有一个单元格,其中包含从 Amazon S3 检索的图像。此图像的高度将影响单元格的高度,但不幸的是,在确定单元格高度后,图像会在完成处理程序中检索。如果我向下和向上滚动,单元格会正确重新加载。

滚动前(单元格高度不正确):

滚动后(正确的单元格高度):

单元配置(一些不必要的东西为了可读性而编辑):

func setCompletionCell(completion: CompletionPublic, contentType: String, classType: String)
        self.completionPub = completion
        self.selectionStyle = UITableViewCellSelectionStyle.None //Disables clicking

        //Setting image or video
        if (contentType == "image")
            nwa.fetchSignedUrl("image/accepted/" + completion.mediaId + ".png")  (result, err) in
                self.nwa.fetchImage(result)  (image, err) in

                    if image != nil
                        let screenSize: CGRect = UIScreen.mainScreen().bounds

                        var multiplyNum = screenSize.width / image.size.width
                        //if image height is going to be more than 60% of the screen, resize width and height to ensure that it isn't greater than 60% while keeping the aspect ratio correct
                        if ((image.size.height*multiplyNum) > (screenSize.height*0.6))
                            multiplyNum = screenSize.height*0.6 / image.size.height
                            self.imageViewWidthConstraint.constant = (multiplyNum*image.size.width)
                            self.imageViewHeightConstraint.constant = screenSize.height*0.6
                        
                        else
                            self.imageViewWidthConstraint.constant = screenSize.width
                            self.imageViewHeightConstraint.constant = (multiplyNum*image.size.height)
                        
                        self.imgView.image = image

                    
                    else
                        //no image returned
                    


                
            
        
        else if (contentType == "video")
            ytplayer.loadWithVideoId(completion.mediaId)
        


    

TableView 委托方法:

func callNWT(tableView: UITableView, completionHandler: () -> ()) 
    switch trendingToggle 
    case 0:
        nwt.getTrendingBounties(0)  (bountyArr, err) in
            //@TODO: change pos
            if bountyArr == nil 
                self.bountyArr = []
            
            else 
                self.bountyArr = bountyArr as [BountyPublic]
            

            if self.bountyArr.count == 0 
                completionHandler()
            
            self.reloadTableViewContent(tableView)
        
    case 1:
        nwt.getTrendingCompletions(0)  (compArr, err) in
            if compArr == nil 
                self.compArr = []
            
            else 
                self.compArr = compArr as [CompletionPublic]
            
            if self.compArr.count == 0 
                completionHandler()
            
            self.reloadTableViewContent(tableView)
        
    case 2:
        nwt.getTrendingPeople(0)  (peopleArr, err) in
            if peopleArr == nil 
                self.peopleArr = []
            
            else 
                self.peopleArr = peopleArr as [Person]
            

            if self.peopleArr.count == 0 
                completionHandler()
            
            self.reloadTableViewContent(tableView)
        
    default:
        break
    


func configureTableView(tableView: UITableView)
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 500.0
    tableView.allowsSelection = false; //disables selection highlighting of cells
    tableView.tableFooterView = UIView()
    tableView.dataSource = self


func reloadTableViewContent(tableView: UITableView) 
    dispatch_async(dispatch_get_main_queue(),  () -> Void in
        tableView.reloadData()
        print("reloading table view content")
        tableView.scrollRectToVisible(CGRectMake(0, 0, 1, 1), animated: false)
    )



func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    if trendingToggle == 0 
        return bountyArr.count
    
    else if trendingToggle == 1 
        return compArr.count
    
    else 
        return peopleArr.count
    



func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
    if trendingToggle == 0 
        return bountyCellAtIndexPath(tableView, indexPath: indexPath)
    
    else if trendingToggle == 1 
        return completedCellAtIndexPath(tableView, indexPath:indexPath)
    
    else 
        return personCellAtIndexPath(tableView, indexPath: indexPath)
    


func completedCellAtIndexPath(tableView: UITableView, indexPath:NSIndexPath) -> CompletedCell
    var cell: CompletedCell
    if compArr[indexPath.row].contentType == "image" 
        cell = tableView.dequeueReusableCellWithIdentifier(completedImgCellIdentifier) as! CompletedCell
        let comp = compArr[indexPath.row]
        cell.setCompletionCell(comp, contentType: "image", classType: "trending")
    
    else  //video
        cell = tableView.dequeueReusableCellWithIdentifier(completedVidCellIdentifier) as! CompletedCell
        let comp = compArr[indexPath.row]
        cell.setCompletionCell(comp, contentType: "video", classType: "trending")
    
    return cell

如何确保第一次正确计算单元格高度?有没有办法可以延迟代码执行,直到检索到图像?或者这不是一个好主意?

【问题讨论】:

发布一些代码,您的表格视图委托方法和单元格配置。 你永远不应该暂停主队列来处理网络请求。你应该做的是在设置图像后你必须通知表格视图布局子视图。 你可以在这里找到示例代码***.com/questions/33975355/… 您应该将下载的图像保存在本地,然后使用“在索引路径重新加载行”tableview 委托方法在完成处理程序中重新加载带有图像的单元格。 如果有成百上千张图片怎么办?我还应该在本地下载它们吗? @Nishant 【参考方案1】:

在完成处理程序中重新加载表格视图。

tableView.reloadData()

在数据源/委托协议的 heightForRowAtIndex 方法中,使用图像重新计算高度并为每个单独的单元格返回适当的值。

当您调用 reloadData() 时,所有数据源/委托方法都会再次调用,因此返回正确的高度将允许您根据需要调整单元格的大小。

【讨论】:

除非图像在本地保存和检索,否则重新加载 tableview 将不起作用。此外,您可以只重新加载该单元格,而不是一次又一次地重新加载整个表格。 你是对的,整个 tableView 不需要重新加载 - 只是有问题的行,但为什么需要在本地保存图像? (我假设您的意思是在应用程序包中)。为什么不能从服务器检索图像将其存储在数据源委托中的数组中,并调用(无论哪种)您喜欢的 reloadTableView 方法,然后在 heightForRowAtIndex 方法中返回与 indexPath.row 中的 indexPath.row 对应的图像的高度图像数组? 通过本地保存然后调用tableView.reloadData() 解决,不再从S3 获取图像。谢谢@Nishant 和布莱克。 @Mitchell:太好了。我建议您在完成处理程序中使用tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) 而不是tableView.reloadData()

以上是关于由于完成处理程序,单元格高度未正确计算的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 单元格未正确显示

UITableView动态单元格高度仅在某些滚动后才能正确显示

iOS - 带有 UITextView 的表格视图单元格未正确调整大小

iOS - 表格视图单元格未正确呈现

UICollectionView 具有自调整大小的单元格未正确计算 contentSize

计算取决于单元格宽度和异步加载的图像的 UITableViewCell 的高度