Подтвердить что ты не робот

Динамический размер 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 здесь: imageImage 2

4b9b3361

Ответ 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