PFQueryTableViewController 中带有图像的动态单元格高度

Posted

技术标签:

【中文标题】PFQueryTableViewController 中带有图像的动态单元格高度【英文标题】:Dynamic cell height in PFQueryTableViewController with images 【发布时间】:2015-06-07 16:49:54 【问题描述】:

简单:我想用屏幕宽度和高度计算的图片大小保持纵横比,类似于9gag app。

如何在 PFQueryTableViewController 中制作单元格的动态高度,在我的单元格中,我在 自定义单元格 中有一个标签和 PFImageView,并且加载工作正常,但图片是不改变单元格的高度,并且所有单元格都具有相同的高度。我被困在这个问题上第三天了,它看起来像是来自 parse.com 框架的错误。我在使用 UITableViewController 时能够更改单元格高度,但解析框架会忽略它。

我正在使用故事板,并尝试使用自动布局约束和不使用它。 TableViewController.swift

import UIKit
import Parse
import ParseUI
import Bolts
class TableViewController: PFQueryTableViewController 

// Initialise the PFQueryTable tableview
override init(style: UITableViewStyle, className: String!) 
    super.init(style: style, className: className)        


required init(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)

    // Configure the PFQueryTableView
    self.pullToRefreshEnabled = true
    self.paginationEnabled = false



// Define the query that will provide the data for the table view
override func queryForTable() -> PFQuery 

    // Start the query object
    var query = PFQuery(className: "Image")
    query.whereKey("deleted", equalTo: 0)
    query.orderByDescending("createdAt")
    return query


//override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? 
    var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell!
    if cell == nil 
        cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CustomCell")
    

    // Extract values from the PFObject to display in the table cell
    if let name = object?["caption"] as? String
        cell.postHeadlineLabel.text = name
    

    // display initial image
    var initialThumbnail = UIImage(named: "question")
    cell.postImageView.image = initialThumbnail
    // extract image
    if let thumbnail = object?["image"] as? PFFile 
        cell.postImageView.file = thumbnail
        cell.postImageView.loadInBackground()
    
    cell.postImageView.contentMode = UIViewContentMode.ScaleAspectFit
    cell.postImageView.clipsToBounds = true

    cell.actualWidth = cell.postImageView.image!.size.width
    cell.actualHeight = cell.postImageView.image!.size.height

    return cell



    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
        var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell!
        let aspect = cell.actualWidth / cell.actualHeight
        var height: CGFloat = cell.postImageView!.frame.size.width * aspect
        return height
    

CustomTableViewCell.swift

import UIKit
import Parse
import ParseUI
class CustomTableViewCell: PFTableViewCell 
 var actualHeight: CGFloat = 10
 var actualWidth: CGFloat = 10
 @IBOutlet weak var postHeadlineLabel: UILabel!
 @IBOutlet weak var postImageView: PFImageView!

我在网上找到了一些建议,但它不起作用,并且似乎是 ios8 解析框架的错误 我试过了

cell.postImageView.contentMode = UIViewContentMode.ScaleAspectFit
cell.postImageView.clipsToBounds = true
cell.sendSubviewToBack(cell.postImageView)

override func awakeFromNib() 
    self.setTranslatesAutoresizingMaskIntoConstraints(false)

更新 - 解析数据库: https://www.anony.ws/image/D6tp

【问题讨论】:

【参考方案1】:

PFQueryTableViewController继承自UITableViewController,这意味着它符合UITableViewDelegate协议。里面有一个你可以重写的方法:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

在这里,您应该根据indexPath 给出的特定单元格的大小返回特定的CGFloat(例如50.0f 50px 或其他)。


更新 1

OP 提供了更多代码来详细说明问题


由于您在tableView:heightForRowAtIndexPath 中调用tableView.dequeueReusableCellWithIdentifier,因此这意味着一旦您准备好一个单元格并准备好图像,那么它将一遍又一遍地继续使用此纵横比。您的 tableView.dequeueReusableCellWithIdentifier 中没有任何逻辑与提供的 indexPath 处的唯一对象相关联。

解决此问题的一种方法是调用objectAtIndexPath(indexPath),这是PFQueryTableViewController 中的一种方法。这将使您能够访问指定单元格中的PFObjectPFFile。这样做的缺点是您必须再次下载图像,从而使用大量带宽。它还会降低您的应用速度,因为您必须等待它下载。

您也可以使用tableView.cellForRowAtIndexPath(indexPath) 为该单元格获取独特的东西,但不幸的是tableView:heightForRowAtIndexPathPFQueryTableViewController 中的tableView:cellForRowAtIndexPath 之前被调用,这将导致应用程序崩溃。


我最好的建议是为您的 Image 类在数据库中添加另一个字段,用于存储图像的纵横比。

如果由于您已经拥有大型数据库或其他一些好的理由而无法做到这一点,那么我建议您制作一个可以计算纵横比的云函数。


更新 2

更新的答案解决方案


在坐下来玩了一会儿之后,我设法为您的问题想出了一个解决方案。不幸的是,它并不漂亮,我仍然建议您将纵横比存储在您的数据库架构中作为最佳解决方案。

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
    return calculateHeightForRowAtIndexPath(indexPath);


func calculateHeightForRowAtIndexPath(indexPath: NSIndexPath) -> CGFloat 
    if let file = objectAtIndexPath(indexPath)?["image"] as? PFFile 
        let image = UIImage(data: file.getData()!)
        let imageToScreenRatio = tableView.bounds.size.width / (image?.size.width)!
        return imageToScreenRatio * (image?.size.height)!
    
    else 
        return 50.0
    

这很糟糕的原因是图像正在使用file.getData() 在主 UI 线程中下载。而是应该使用file.getDataInBackgroundWithBlock(block),但这会导致问题,因为calculateHeightForRowAtIndexPath 会在下载图像之前返回。


更新 3

OP 提供了有关 DB 架构的更多信息


由于您已经将比率存储在数据库中,因此您可以通过以下方式计算单元格高度:

func calculateHeightForRowAtIndexPath(indexPath: NSIndexPath) -> CGFloat 
    if let ratio = objectAtIndexPath(indexPath)?["aspect"] as? Float 
        return tableView.bounds.size.width / CGFloat(ratio)
    
    else 
        return 50.0
    

【讨论】:

我试过了,但它改变了每个单元格的单元格高度......我还尝试计算高度:override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell! let aspect = cell.actualWidth / cell.actualHeight var height: CGFloat = cell.postImageView!.frame.size.width * aspect return height actualWidth var I did in cellForRowAtInd cell.actualWidth = cell.postImageView.image!.size.width 根据其内容调整单元格的大小与 Parse 无关,这都是 iOS 的东西,所以把你的愤怒发泄在 Apple xD 上,不过,一旦你掌握了它的窍门,那就是它将是第二天性。 关于下载额外的东西:如果您已经将比率存储在Image 架构中,那么它会自动与其他数据一起下载。您能否使用 Parse 的数据库打印屏幕更新您的问题? 这与自动布局无关,这纯粹是关于UITableViewController。它总共有大约 40-50 个委托方法,因此知道要使用哪些委托方法可能会让人不知所措,但希望你现在已经可以使用它了 :) 这开始偏离您原来的问题Dynamic cell height in PFQueryTableViewController with images 的话题,而更多地转向PFQueryTableViewController with pagination enabled 之类的问题。我建议您创建一个新问题,其中包含相关部分的代码 sn-ps,然后如果您想让我看一下,您可以链接到这些 cmets 中的问题 :) 我发布了new question,任何帮助将不胜感激【参考方案2】:

您正在实施的是错误的方法。 在 cellForRowAtIndexPath 之前调用 heightForRowAtIndexPath。因此,它将在您的方法中返回错误的值。尝试改用设备宽度。根据我对您要求的理解,我在下面进行了更改。尝试一下并做出相应的更改,如果它有效,请告诉我..

在你的 heightForRowAtIndexPath 中,尝试改变

#define ASPECT_RATIO 0.5f
var height: CGFloat = UIScreen.mainScreen().bounds.size.width * ASPECT_RATIO

这将使单元格的高度成为设备宽度的一半。 您可以根据需要更改纵横比的值。如果你有标签,你可以在高度变量中添加它的高度。

【讨论】:

我试过了,但无法编译。我想要的是单元格内图像的宽度与单元格的宽度相同,并且由图像的纵横比计算的高度 - 每个图像将具有相同的宽度并且高度将是动态的跨度> 在计算高度之前应该先下载你的图像,这样你就可以计算图像的大小。我对此有一个想法。如果您可以在 PFClass 中存储图像的大小(或图像的纵横比),则可以检索它并事先计算高度。

以上是关于PFQueryTableViewController 中带有图像的动态单元格高度的主要内容,如果未能解决你的问题,请参考以下文章