Динамическая высота ячейки в PFQueryTableViewController с изображениями
Просто: я хочу, чтобы размер картинки с шириной экрана и высотой вычислялся, чтобы сохранить соотношение сторон, как в приложении 9gag.
Как я могу сделать динамическую высоту ячейки в PFQueryTableViewController, в моей ячейке у меня есть одна метка и PFImageView в пользовательской ячейке, и загрузка работает нормально, но изображения не меняют высоту ячейки, и все ячейки имеют одинаковую высоту. Я застрял на этой проблеме в третий день, и это похоже на ошибку в рамках parse.com. Мне удалось изменить высоту ячейки, когда я работал с UITableViewController, но структура синтаксического анализа игнорирует ее.
Я использую раскадровку и попробовал это с ограничением autolayout и без него.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
2 ответа
PFQueryTableViewController
наследуется от UITableViewController
Это означает, что он соответствует UITableViewDelegate
протокол. Внутри есть метод, который вы можете переопределить:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
Здесь вы должны вернуть конкретный CGFloat
(например 50.0f
за 50 пикселей или что-то еще) в зависимости от размера этой конкретной ячейки, заданной indexPath
,
ОБНОВЛЕНИЕ 1:
ОП предоставил больше кода для проработки проблемы
Так как ты звонишь tableView.dequeueReusableCellWithIdentifier
в tableView:heightForRowAtIndexPath
, тогда это означает, что как только у вас будет одна ячейка с готовым изображением, она будет снова и снова использовать это соотношение сторон. В твоей логике нет tableView.dequeueReusableCellWithIdentifier
который привязан к уникальному объекту при условии indexPath
,
Одним из способов преодоления этого может быть позвонив objectAtIndexPath(indexPath)
, который является методом из PFQueryTableViewController
, Это даст вам доступ к PFObject
а также PFFile
в указанной ячейке. Недостатком этого является то, что вам придется снова загружать изображение, используя большую ширину полосы. Это также замедлит работу вашего приложения, так как вам придется ждать его загрузки.
Вы также можете использовать tableView.cellForRowAtIndexPath(indexPath)
чтобы получить что-то уникальное для этой клетки, но, к сожалению, tableView:heightForRowAtIndexPath
называется раньше tableView:cellForRowAtIndexPath
в PFQueryTableViewController
что приведет к сбою приложения.
Мое лучшее предложение - добавить еще одно поле в базу данных для вашего 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()
, Вместо file.getDataInBackgroundWithBlock(block)
следует использовать, но это может вызвать проблемы, так как calculateHeightForRowAtIndexPath
затем вернется, прежде чем загрузить изображение.
ОБНОВЛЕНИЕ 3
ОП предоставил больше информации о схеме БД
Поскольку у вас уже есть соотношение, хранящееся в базе данных, вы можете рассчитать высоту ячейки следующим образом:
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. Таким образом, он вернет неправильные значения в вашем методе. Попробуйте вместо этого использовать ширину устройства. Я внес изменения ниже в соответствии с моим пониманием вашего требования. Попробуйте и сделайте некоторые изменения соответственно и дайте мне знать, если это сработало..
В вашем heightForRowAtIndexPath попробуйте изменить
#define ASPECT_RATIO 0.5f
var height: CGFloat = UIScreen.mainScreen().bounds.size.width * ASPECT_RATIO
В этом случае высота ячейки будет равна половине ширины устройства. Вы можете изменить значение соотношения сторон в соответствии с вашими требованиями. Если у вас есть метка, вы можете добавить ее высоту в переменной высоты.