简体   繁体   English

UICollectionViewCell在设备旋转时调整大小

[英]UICollectionViewCell resizing on device rotation

I have a very simple UICollectionView embedded in a ViewController. 我在ViewController中嵌入了一个非常简单的UICollectionView。

The UICollectionView uses auto-layout (defined in IB) to take the whole space in the ViewController. UICollectionView使用自动布局(在IB中定义)来占用ViewController中的整个空间。

My UICollectionViewCell have all the same size and they take the whole space of the UICollectionView because I want only one cell to be displayed in the ViewController. 我的UICollectionViewCell具有相同的大小,它们占据了UICollectionView的整个空间,因为我只希望在ViewController中显示一个单元格。 The UICollectionViewCell displays only an UIImage (which is embedded in a UIScrollView for zooming). UICollectionViewCell仅显示一个UIImage(嵌入在UIScrollView中以进行缩放)。

It works fine except when the device rotate. 除非设备旋转,否则它工作正常。 There's an error message: 出现错误消息:

The behavior of the UICollectionViewFlowLayout is not defined because: the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values. 未定义UICollectionViewFlowLayout的行为,因为:项目高度必须小于UICollectionView的高度减去该部分插入的上限值和下限值,减去内容插入的上限值和下限值。 The relevant UICollectionViewFlowLayout instance is , and it is attached to ; 相关的UICollectionViewFlowLayout实例为,并附加到; animations = { bounds.origin=; 动画= {bounds.origin =; bounds.size=; bounds.size =; position=; position =; }; }; layer = ; 层=; contentOffset: {0, 0}; contentOffset:{0,0}; contentSize: {4875, 323}> collection view layout: . contentSize:{4875,323}>集合视图布局:。

That's pretty clear, I need to resize my UICollectionViewCell to fit the new height / width. 这很清楚,我需要调整UICollectionViewCell的大小以适合新的高度/宽度。 After the rotation the UICollectionViewCell display with the appropriate height / width but with a poor animation. 旋转后,UICollectionViewCell将显示适当的高度/宽度,但动画效果不佳。

Here's the code: 这是代码:

@IBOutlet weak var theCollectionView: UICollectionView!
@IBOutlet weak var theFlowLayout: UICollectionViewFlowLayout!
    override func viewDidLoad() {
    super.viewDidLoad()

    //theCollectionView.delegate = self
    theCollectionView.dataSource = self
    automaticallyAdjustsScrollViewInsets = false
    theFlowLayout.itemSize = theCollectionView.frame.size
    theFlowLayout.sectionInset = UIEdgeInsetsMake(0,0,0,0)
    theFlowLayout.minimumLineSpacing = 0.0
    theCollectionView.reloadData()
}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    print("\(#function) \(view.frame.size)")
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        self.theFlowLayout.itemSize = self.theCollectionView.frame.size
    })        
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    print("\(#function) \(view.frame.size)")
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    print("\(#function) \(view.frame.size)")
}

The question is, how and when perform the UICollectionViewCell change to avoid the warning and get the smooth animation? 问题是,如何以及何时执行UICollectionViewCell更改以避免警告并获得平滑的动画?

When the device rotation happens, I can see the following: viewWillTransition(to:with:) (375.0, 667.0) viewWillLayoutSubviews() (667.0, 375.0) viewDidLayoutSubviews() (667.0, 375.0) 当设备旋转时,我可以看到以下内容:viewWillTransition(to:with :)(375.0,667.0)viewWillLayoutSubviews()(667.0,375.0)viewDidLayoutSubviews()(667.0,375.0)

The error is displayed just after the viewDidLayoutSubviews(). 该错误仅在viewDidLayoutSubviews()之后显示。 I have tried to call theFlowLayout.invalidateLayout() in viewDidLayoutSubviews() but it doesn't change the issue. 我试图在viewDidLayoutSubviews()中调用theFlowLayout.invalidateLayout(),但它不会改变问题。

I have read others similar questions but I could not find my answer :-( 我读过其他类似的问题,但找不到答案:-(

Thanks for your help, 谢谢你的帮助,

Sebastien 塞巴斯蒂安

I have not found the best solution but at least it works. 我还没有找到最好的解决方案,但至少可以奏效。

I use viewWillTransition to compute the index of the cell and to reset the offset after the rotation. 我使用viewWillTransition计算单元格的索引并在旋转后重置偏移量。 To avoid poor animation I set the alpha to 0 and at the beginning and to 1 again at the end of the animation. 为避免动画效果不佳,我将Alpha设置为0,并在动画的开始处将其设置为1,然后在动画结束时将其设置为1。

viewWillLayoutSubviews is used to invalidated the layout of the UICollectionViewFlowLayout and viewDidLayoutSubviews to set the new cell size. viewWillLayoutSubviews用于使UICollectionViewFlowLayout和viewDidLayoutSubviews的布局无效以设置新的单元格大小。

Maybe it will help others but if you have a better solution, please share it! 也许会对其他人有所帮助,但是如果您有更好的解决方案,请与我们分享!

    @IBOutlet weak var theCollectionView: UICollectionView! {
    didSet {
        theCollectionView.backgroundColor = UIColor.black
        theCollectionView.delegate = self
        theCollectionView.dataSource = self
    }
}

@IBOutlet weak var theFlowLayout: UICollectionViewFlowLayout! {
    didSet {
        theFlowLayout.itemSize = theCollectionView.frame.size
        theFlowLayout.sectionInset = UIEdgeInsetsMake(0,0,0,0)
        theFlowLayout.minimumLineSpacing = 0.0
    }
}

var assets:[PHAsset]!
var startAssetIndex = 0

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.black
    automaticallyAdjustsScrollViewInsets = false
    theCollectionView.reloadData()
}


override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    theCollectionView.scrollToItem(at: IndexPath(row:startAssetIndex, section:0), at: .left, animated: true)
}


/// Resize the collectionView during device rotation
///
/// - Parameters:
///   - size: New size of the viewController
///   - coordinator: coordinator for the animation
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)

    // Compute the index of the image/video currently displayed
    let offset = self.theCollectionView.contentOffset;
    let index = round(offset.x / self.theCollectionView.bounds.size.width);

    // hide the collection view to avoid horrible animation during the rotation
    // animation is horrible due to the offset change
    theCollectionView.alpha = 0.0
    coordinator.animate(alongsideTransition: nil, completion: {
        _ in
        // display the collectionView during the animation
        self.theCollectionView.alpha = 1.0

        // compute the new offset based on the index and the new size
        let newOffset = CGPoint(x: index * self.theCollectionView.frame.size.width, y: offset.y)
        self.theCollectionView.setContentOffset(newOffset, animated: false)
    })
}


/// Invalidate the layout of the FlowLayout, it's mandatory for the rotation
override func viewWillLayoutSubviews() {
    theFlowLayout.invalidateLayout()
    super.viewWillLayoutSubviews()
}


/// Set the size of the items (mandatory for the rotation)
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    theFlowLayout.itemSize = theCollectionView.frame.size
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM