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

Dynamic cell height in PFQueryTableViewController with images

简单:我想要图片的尺寸和屏幕的宽度和高度计算保持宽高比,类似于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

PFQueryTableViewController继承自UITableViewController,即符合UITableViewDelegate协议。这里有一个你可以覆盖的方法,叫做:

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

在这里你应该return一个特定的CGFloat(例如50.0f代表50px或其他)取决于[=18=给出的特定单元格的大小].


更新 1:

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


由于您在 tableView:heightForRowAtIndexPath 中调用 tableView.dequeueReusableCellWithIdentifier,这意味着一旦您准备好一个带有图像的单元格,它就会不断地使用这个纵横比.您的 tableView.dequeueReusableCellWithIdentifier 中没有逻辑,它与提供的 indexPath.

中的唯一对象相关联

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

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


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

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


更新 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 会在下载图像之前 return。


更新 3

OP 提供了有关数据库架构的更多信息


既然你已经将比例存储在数据库中,那么你可以通过以下方式计算单元格高度:

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

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

在您的 heightForRowAtIndexPath 中,尝试更改

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

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