Я хочу отобразить NSCollectionLayoutItem (содержит изображение с удаленного устройства, а его соотношение сторон неизвестно), занять экран устройства по горизонтали и при этом получить правильное соотношение сторон по вертикали.
Поэтому я использую точки NSCollectionLayoutDimension.estimated(50) для высоты. но после загрузки изображения высота по-прежнему равна 50, чего недостаточно для отображения изображения.
Как сделать так, чтобы макет автоматически соответствовал содержимому изображения.
ссылка на изображение находится здесь: [image src] (https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png)
содержание изображения:
и результат работы будет таким
код конфигурации UICollectionView:
import UIKit
class ViewController: UIViewController {
enum Section {
case main
}
@IBOutlet weak var collectionView: UICollectionView!
var dataSource: UICollectionViewDiffableDataSource<Section, Int>! = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.configDataSource()
self.configLayout()
}
func configDataSource() {
let imageCellReg = UICollectionView.CellRegistration<ImageCell,Int>(cellNib: UINib(nibName: "ImageCell", bundle: nil)) { cell, indexPath, itemIdentifier in
}
self.dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: self.collectionView, cellProvider: { collectionView, indexPath, itemIdentifier in
return self.collectionView.dequeueConfiguredReusableCell(using: imageCellReg, for: indexPath, item: itemIdentifier)
})
var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
snapshot.appendSections([.main])
snapshot.appendItems(Array(0..<2))
dataSource.apply(snapshot, animatingDifferences: false)
}
func configLayout(){
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension:.estimated(50))
let group = NSCollectionLayoutGroup.horizontal(layoutSize:groupSize, subitems: [item])
let spacing = CGFloat(10)
group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
let layout = UICollectionViewCompositionalLayout(section: section)
self.collectionView.collectionViewLayout = layout
}
}
И код ячейки:
import UIKit
import SDWebImage
class ImageCell: UICollectionViewCell {
@IBOutlet weak var imageContentView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
imageContentView.sd_setImage(with: URL(string: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"))
}
}
@DonMag, это более точная проблема из предыдущего вопроса
Лучше не публиковать новый вопрос — лучше продолжить обсуждение с людьми, которые уже ответили. Я бы посоветовал вам зайти в свою любимую поисковую систему и поискать SDWebImage set uicollectionviewcell height after download... уже существует множество обсуждений и примеров.
@DonMag, это не имеет ничего общего с SDWebImage. На самом деле проблема в том, что вы не можете установить правильную высоту для ячейки, если сначала не знаете точное соотношение сторон. И если вы сбросите ячейку после загрузки с соотношением сторон просто получите. В большинстве ситуаций это означает повторную перезагрузку изображения. и вызвать бесконечный цикл (возможно, есть какие-то способы избежать этого цикла), но я думаю, что для этого сценария должна быть хорошая практика.
@DonMag, может быть, ты сможешь написать демо-версию для отображения изображения значка Google с удаленного компьютера с помощью uicollectionviewcompositionallayout, и ты поймешь, что я путаю ~
@ximmyxiao, я получаю вот такой результат ibb.co/wpNqrQs
используется тот же код? Это нормально ?
@Shivbaba'sson, спасибо, код DonMan для меня очень полезен ~





Очень быстрый пример...
Создайте свою ячейку следующим образом:
Мы задали для представления изображения ограничение по высоте, которое будет обновляться при загрузке изображения.
Класс ячейки очень прост:
class ImageCell: UICollectionViewCell {
@IBOutlet var imageContentView: UIImageView!
@IBOutlet var imgHeight: NSLayoutConstraint!
}
Используя SDWebImage, мы реализуем блок завершения, в котором рассчитаем высоту соотношения сторон для загруженного изображения, которую мы будем использовать для установки imgHeight.constant. Затем мы вызываем collectionView.collectionViewLayout.invalidateLayout(), чтобы сообщить контроллеру изменить расположение ячеек:
cell.imageContentView.sd_setImage (
with: URL(string: urlStr),
placeholderImage: UIImage(named: "somePlaceholder"),
options: SDWebImageOptions(rawValue: 0),
completed: { [weak self] image, error, cacheType, imageURL in
guard let self = self,
let img = image
else { return }
// calculate proportional height
let iw = cell.imageContentView.frame.width
let ih = (img.size.height / img.size.width) * iw
// update the height contraint in the cell
cell.imgHeight.constant = ih
// tell the collection view to re-layout the cells
self.collectionView.collectionViewLayout.invalidateLayout()
}
)
Вот полный пример проекта: https://github.com/DonMag/SDWebCV
Спасибо, похоже, validateLayout не перезагрузит ячейку, поэтому бесконечного цикла не будет, я использую для вызова reloadData/Item в блоке завершения. очень полезно это узнать~!
Я вижу ограничение по высоте для ячейки, добавленной в проект. Должно ли это ограничение существовать? или функция самостоятельного определения размера может делать то же самое без ограничения высоты?
@ximmyxiao - вам нужно что-то сделать, чтобы сообщить представлению коллекции, какой высоты сделать ячейку. Это один из подходов. Вы не предоставили никаких подробностей, связанных с чем-либо еще, что вы, возможно, захотите сделать со своим пользовательским интерфейсом... вы можете использовать собственный макет вместо CompositionalLayout, но я понятия не имею, какова ваша конечная цель.
Фактически, я реорганизую страницу с флаттера на собственный код iOS и обнаружил, что List+Image будет хорошо работать для изображений любого размера без необходимости сброса высоты. Итак, я хочу знать, можно ли сделать то же самое в собственном коде iOS. потому что я думал, что механизм самостоятельного определения размера в iOS может работать так же, как флаттер, и мне не нужно устанавливать высоту вручную. но похоже я ошибаюсь @DonMag
@ximmyxiao — я ничего не знаю о Flutter или его компонентах пользовательского интерфейса. В iOS для UIImageView можно установить .scaleToFill, .scaleAspectFit, .scaleAspectFill (и некоторые менее распространенные режимы), чтобы контролировать размер изображения внутри рамки просмотра, но у него нет возможности «изменить рамку просмотра в соответствии с изображением». Вы могли бы создать подкласс UIImageView, чтобы получить эту функциональность, но... есть ли причина, по которой вы не хотите использовать метод ограничения, который я вам дал?
Спасибо @DonMag, потому что в большинстве случаев вам не нужно устанавливать ограничение высоты для ячейки, механизм самостоятельного определения размера UIKit установит правильную высоту для ячейки. (например, ячейка имеет только метку). Я думаю, что такой макет «ячейка без ограничения по высоте» более прост в использовании, чем макет «ячейка должна установить ограничение по высоте». Но, как вы говорите: само изображение не имеет возможности «изменить рамку просмотра в соответствии с изображением». Итак, кажется, что если я хочу создать ячейку без ограничения по высоте, мне нужно создать подкласс UIImageView и перезаписать его встроенныйContentSize
@ximmyxiao - да, если вы хотите, чтобы компонент пользовательского интерфейса имел свойства/поведения, отличные от его по умолчанию, вам необходимо создать его подкласс. В опубликованном вами коде вы уже создаете подклассы UIViewController и UICollectionViewCell... поэтому создание подклассов UIImageView будет просто еще одним шагом для получения желаемых результатов.
Это отличается от вашего предыдущего вопроса? stackoverflow.com/questions/78370684/…