[英]Change layout of UICollectionViewCell
I am using a UICollectionViewController to display a collection of UICollectionViewCell that a user can swipe between, on ios 13, swift 5, and UIKit.我正在使用 UICollectionViewController 来显示用户可以在 ios 13、swift 5 和 UIKit 之间滑动的 UICollectionViewCell 集合。 I ultimatelly want to re-draw the cell if the user has changed the orientation.如果用户更改了方向,我最终想重新绘制单元格。 In my controller, I have noticed that this piece of code gets executed on orientation change:在我的控制器中,我注意到这段代码在方向改变时执行:
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! MyCell
return cell
}
In MyCell, I am using this code to monitor then a layout is re-initialized:在 MyCell 中,我使用此代码进行监视,然后重新初始化布局:
override init(frame: CGRect) {
super.init(frame: frame)
setLayout()
print("### orientation:: \(UIDevice.current.orientation.isLandscape) ")
}
Result: This method is called 2 times.结果:该方法被调用了 2 次。 When the app starts, and when I change from portrait to landscape.当应用程序启动时,以及当我从纵向变为横向时。 Any subsequent changes, do not call it.任何后续更改,不要调用它。 I suspect that this is fine, as maybe both versions are cached ( a landscape and a portrait ).我怀疑这很好,因为可能两个版本都被缓存(横向和纵向)。 If I add code to the setLayout() method based on the UIDevice.current.orientation.isLandscape flag, nothing changes while it executes.如果我根据 UIDevice.current.orientation.isLandscape 标志向 setLayout() 方法添加代码,则在执行时不会发生任何变化。 Note: The actual result of UIDevice.current.orientation.isLandscape is correct.注意: UIDevice.current.orientation.isLandscape 的实际结果是正确的。
Here is an example of what is in my setLayout() method:这是我的 setLayout() 方法中的示例:
let topImageViewContainer = UIView();
topImageViewContainer.translatesAutoresizingMaskIntoConstraints = false
topImageViewContainer.backgroundColor = .yellow
addSubview(topImageViewContainer)
NSLayoutConstraint.activate([
topImageViewContainer.topAnchor.constraint(equalTo: topAnchor),
topImageViewContainer.leftAnchor.constraint(equalTo: leftAnchor),
topImageViewContainer.rightAnchor.constraint(equalTo: rightAnchor),
topImageViewContainer.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5)
])
if (UIDevice.current.orientation.isLandscape) {
let imageView = UIImageView(image: UIImage(named: "photo_a"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
topImageViewContainer.addSubview(imageView)
} else {
let imageView = UIImageView(image: UIImage(named: "photo_b"))
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
topImageViewContainer.addSubview(imageView)
}
In the example above, the code with "photo_a" is executing, but the ui is still showing photo_b.在上面的例子中,带有“photo_a”的代码正在执行,但ui仍然显示photo_b。 I suspect I am doing something wrong, and I need to somehow migrate towards an "Adaptive layout" as mentioned here: Different layouts in portrait and landscape mode .我怀疑我做错了什么,我需要以某种方式迁移到这里提到的“自适应布局”: 不同的布局在纵向和横向模式。 However, I am not sure how I could hook in some "viewWillTransition*" functions into a UICollectionViewCell that has a UIView.但是,我不确定如何将某些“viewWillTransition*”函数挂钩到具有 UIView 的 UICollectionViewCell 中。
How can I adjust my MyCell class, that implements UICollectionViewCell, to allow the cell to be updated when the user changes from landscape to protrait in a Swift intended way?如何调整实现 UICollectionViewCell 的 MyCell 类,以允许在用户以 Swift 预期的方式从横向变为纵向时更新单元格?
Hi try to check if is landscape or portrait in cellForItem, my example: set colloectionView, flowLayaout and cell id:嗨,尝试检查 cellForItem 中是横向还是纵向,我的示例:设置 colloectionView、flowLayaout 和单元格 id:
class ViewController: UIViewController {
private var collectionView: UICollectionView?
let layout = UICollectionViewFlowLayout()
let cellId = "cellId"
now in viewDidLoad set collection view and layout parameters and the collection constraints:现在在 viewDidLoad 中设置集合视图和布局参数以及集合约束:
layout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView?.delegate = self
collectionView?.dataSource = self
collectionView?.backgroundColor = .clear
collectionView?.register(BottomCellTableViewCell.self, forCellWithReuseIdentifier: cellId)
collectionView?.contentInset = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.translatesAutoresizingMaskIntoConstraints = false
guard let collection = collectionView else { return }
view.addSubview(collection)
layout.itemSize = CGSize(width: view.bounds.size.width / 2, height: 200)
collection.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -20).isActive = true
collection.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0).isActive = true
collection.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0).isActive = true
collection.heightAnchor.constraint(equalToConstant: 200).isActive = true
after that conform to delegate and datasource in a separate extension (more clean code) and set in it numberOfItems and cellForRow:之后在单独的扩展中符合委托和数据源(更干净的代码)并在其中设置 numberOfItems 和 cellForRow:
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! BottomCellTableViewCell
// check here device orientation
if UIDevice.current.orientation.isLandscape {
let image = UIImage(named: "meB")
cell.imageV.image = image
} else {
let image = UIImage(named: "me")
cell.imageV.image = image
}
// reload the view and the collection
DispatchQueue.main.async {
self.collectionView?.reloadData()
}
return cell
}
}
In collectionViewCell adding a subview directly to the cell, and pinning the image view to the cell, is wrong.在 collectionViewCell 中直接向单元格添加子视图,并将图像视图固定到单元格,是错误的。 You add it to a contentView and pin to it relative constraints:您将其添加到 contentView 并固定到它的相对约束:
class BottomCellTableViewCell: UICollectionViewCell {
let imageV: UIImageView = {
let iv = UIImageView()
iv.image = UIImage(named: "me")
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
contentView.backgroundColor = .red
contentView.addSubview(imageV)
imageV.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
imageV.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
imageV.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
imageV.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
This is the result:这是结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.