Динамический размер UIImageView внутри UITableView
Я хочу реализовать TableView с пользовательским TableViewCell, отображающим изображение.
Чтобы сделать это простым, я просто поместил UIImageView внутри tableviewcell, используя автозапуск (см. ниже).
![введите описание изображения здесь]()
Я хочу отображать изображение внутри UIImageView, но эти размеры изображений могут быть любыми и непоследовательными (портрет, пейзаж, квадрат)...
Поэтому я ищу для отображения изображения с фиксированной шириной (шириной устройства) и динамической высотой, которые соотносятся с отношением изображений. Я хочу что-то вроде этого:
![введите описание изображения здесь]()
Мне, к сожалению, не удалось достичь этого результата.
Вот как я его реализовал - (я использую Haneke для загрузки изображения из URL-изображения, хранящегося в Amazon S3):
class TestCellVC: UITableViewCell {
@IBOutlet weak var selfieImageView: UIImageView!
@IBOutlet weak var heightConstraint: NSLayoutConstraint!
func loadItem(#selfie: Selfie) {
let selfieImageURL:NSURL = NSURL(string: selfie.show_selfie_pic())!
self.selfieImageView.hnk_setImageFromURL(selfieImageURL, placeholder: nil, format: HNKFormat<UIImage>(name: "original"), failure: {error -> Void in println(error)
}, success: { (image) -> Void in
// Screen Width
var screen_width = UIScreen.mainScreen().bounds.width
// Ratio Width / Height
var ratio = image.size.height / image.size.width
// Calculated Height for the picture
let newHeight = screen_width * ratio
// METHOD 1
self.heightConstraint.constant = newHeight
// METHOD 2
//self.selfieImageView.bounds = CGRectMake(0,0,screen_width,newHeight)
self.selfieImageView.image = image
}
)
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Register the xib for the Custom TableViewCell
var nib = UINib(nibName: "TestCell", bundle: nil)
self.tableView.registerNib(nib, forCellReuseIdentifier: "TestCell")
// Set the height of a cell dynamically
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 500.0
// Remove separator line from UITableView
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
loadData()
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("TestCell") as TestCellVC
cell.loadItem(selfie: self.selfies_array[indexPath.row])
// Remove the inset for cell separator
cell.layoutMargins = UIEdgeInsetsZero
cell.separatorInset = UIEdgeInsetsZero
// Update Cell Constraints
cell.setNeedsUpdateConstraints()
cell.updateConstraintsIfNeeded()
cell.sizeToFit()
return cell
}
Мой расчет динамической высоты правильный (я его распечатал). Я пробовал оба метода (описать в коде), но никто из них не работал:
- Установить ограничение автоопределения высоты в UIImageView
- Измените кадр UIImageView
См. результаты метода 1 и 2 здесь:
![image]()
![Image 2]()
Ответы
Ответ 1
В раскадровке добавьте к вашему UIImageView
конечные, ведущие, нижние и верхние ограничения. После загрузки изображения все, что вам нужно сделать, это добавить ограничение размера к вашему UIImageView
. Ваша ячейка изображений будет выглядеть примерно так:
class ImageTableViewCell: UITableViewCell {
@IBOutlet weak var customImageView: UIImageView!
internal var aspectConstraint : NSLayoutConstraint? {
didSet {
if oldValue != nil {
customImageView.removeConstraint(oldValue!)
}
if aspectConstraint != nil {
customImageView.addConstraint(aspectConstraint!)
}
}
}
override func prepareForReuse() {
super.prepareForReuse()
aspectConstraint = nil
}
func setCustomImage(image : UIImage) {
let aspect = image.size.width / image.size.height
let constraint = NSLayoutConstraint(item: customImageView, attribute: NSLayoutAttribute.width, relatedBy: NSLayoutRelation.equal, toItem: customImageView, attribute: NSLayoutAttribute.height, multiplier: aspect, constant: 0.0)
constraint.priority = 999
aspectConstraint = constraint
customImageView.image = image
}
}
Здесь вы можете проверить рабочий пример DynamicTableWithImages
Ответ 2
Если вы хотите, чтобы UIImageView сообщал UITableView, насколько высок он должен быть, вам нужно настроить представление таблицы, чтобы включить автоматический расчет строк. Вы делаете это, устанавливая оценочное значение RowHeight на фиксированное положительное значение и устанавливая rowHeight для UIViewAutomaticDimension. Это первая часть.
Теперь вам нужно настроить UIImageView на запрос высоты, основанной на ширине, которая требуется для просмотра таблицы, и соотношении сторон изображения. Это будет вторая часть.
Сначала установите для параметра contentMode значение .AspectFit. Это приведет к тому, что вид изменит внешний вид изображения на основе любых измерений. Тем не менее, это все еще не заставляет его запрашивать необходимую высоту с автоматическим расположением. Вместо этого он запрашивает высоту intrinsicContentSize, которая может сильно отличаться от измененного изображения. Итак, во-вторых, добавьте ограничение в UIImageView, имеющее форму width = height * multiplier
, где множитель основан на соотношении сторон самого изображения.
Теперь для представления таблицы потребуется правильная ширина, механизм contentMode гарантирует правильное изменение размера изображения без искажений, а ограничение размера изображения гарантирует, что представление изображения требует правильной высоты с помощью автоматической компоновки.
Это работает. Недостатком этого является то, что вам нужно будет обновить ограничение соотношения сторон каждый раз, когда вы назначаете новое изображение на изображение, что может быть довольно часто, если изображение отображается в ячейке, которая повторно используется.
Альтернативный подход состоит в том, чтобы добавить только ограничение высоты и обновить его в layoutSubviews представления, содержащего представление изображения. Это имеет лучшую производительность, но хуже модульность кода.
Ответ 3
Удалите ограничение высоты из вашего изображения. Выберите contentMode представления изображения, который начинается с "аспекта", например: аспект заполнения или соответствия аспект (по мере того, как он соответствует вашим требованиям).
ПРИМЕЧАНИЕ. Вам также необходимо установить высоту строки так, чтобы в нее входил образ. Используйте
heightForRowAtIndexPath
чтобы установить пользовательскую высоту строки.
Ответ 4
![введите описание изображения здесь]()
При загрузке изображений в таблицуView каждое изображение может иметь разное соотношение сторон.
С помощью SDWebImage мы можем получить изображение с URL-адреса как -
testImageView.sd_setImage(with: url, placeholderImage: nil, options: [], completed: { (downloadedImage, error, cache, url) in
print(downloadedImage?.size.width)//prints width of image
print(downloadedImage?.size.height)//prints height of image
})
В UITableViewCell
установите ограничение для imageView как top
, bottom
, leading
, trailing
, fixed height constraint
с приоритетом 999
И измените height-constraint-constant
в соответствии с изображением.
var cellFrame = cell.frame.size
cellFrame.height = cellFrame.height - 15
cellFrame.width = cellFrame.width - 15
cell.feedImageView.sd_setImage(with: url, placeholderImage: nil, options: [], completed: { (theImage, error, cache, url) in
cell.feedImageHeightConstraint.constant = self.getAspectRatioAccordingToiPhones(cellImageFrame: cellFrame,downloadedImage: theImage!)
})
Рассчитайте кадр ячейки и найдите соответствующую высоту на основе этого.
func getAspectRatioAccordingToiPhones(cellImageFrame:CGSize,downloadedImage: UIImage)->CGFloat {
let widthOffset = downloadedImage.size.width - cellImageFrame.width
let widthOffsetPercentage = (widthOffset*100)/downloadedImage.size.width
let heightOffset = (widthOffsetPercentage * downloadedImage.size.height)/100
let effectiveHeight = downloadedImage.size.height - heightOffset
return(effectiveHeight)
}
Пример для Github