You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iPhone SE模拟器CollectionView异常,iPhone 11正常的问题求助

Hey there! Let's figure out why you're getting that weird blank cell on smaller devices like the iPhone SE.

What's Causing the Issue?

Looking at your code, I see two main potential culprits:

  • One-time item size calculation: Your setupCollectionViewItemSize() only calculates the item width once (when collectionViewFlowLayout is nil). Even though this runs on first launch for each device, if the collection view's final bounds aren't set yet when viewWillLayoutSubviews fires, you might be using an incorrect width value.
  • Floating-point precision issues: When you calculate the item width, dividing the collection view's width by 3 might result in a fractional value. Adding up 3 of those plus the inter-item spacing could push the total width just over the collection view's bounds, forcing the third cell to wrap to the next row—leaving a blank spot where it should be.

Fixes to Try

Let's go through two solid solutions, starting with the simplest tweak to your existing code, then a more robust approach using collection view delegates.

Solution 1: Update Item Size Every Time Layout Changes

Modify your setupCollectionViewItemSize() to recalculate the item size on every layout update, not just when the flow layout is first created. We'll also use floor() to avoid fractional widths that cause overflow:

private func setupCollectionViewItemSize(){
    let numberOfItemsPerRow: CGFloat = 3
    let lineSpacing: CGFloat = 5
    let interItemSpacing: CGFloat = 5
    
    // Use bounds.width instead of frame.width—it's more reliable for layout calculations
    let availableWidth = collectionView.bounds.width - (numberOfItemsPerRow - 1) * interItemSpacing
    // Floor the width to eliminate fractional values that cause layout overflow
    let width = floor(availableWidth / numberOfItemsPerRow)
    let height = width

    if collectionViewFlowLayout == nil {
        collectionViewFlowLayout = UICollectionViewFlowLayout()
        collectionViewFlowLayout.sectionInset = UIEdgeInsets.zero
        collectionViewFlowLayout.scrollDirection = .vertical
        collectionViewFlowLayout.minimumLineSpacing = lineSpacing
        collectionViewFlowLayout.minimumInteritemSpacing = interItemSpacing
        collectionView.setCollectionViewLayout(collectionViewFlowLayout, animated: false)
    }
    
    // Update the item size EVERY time this method runs
    collectionViewFlowLayout.itemSize = CGSize(width: width, height: height)
}

Solution 2: Use UICollectionViewDelegateFlowLayout (More Robust)

For better control and adherence to collection view best practices, use the delegate methods to dynamically return item sizes and spacing. This way, the system asks for these values whenever it needs to layout the collection view:

First, make sure your view controller conforms to UICollectionViewDelegateFlowLayout (you probably already conform to UICollectionViewDelegate and UICollectionViewDataSource, so just add it):

class YourViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    // ... your existing code ...
}

Then remove the setupCollectionViewItemSize() method and the collectionViewFlowLayout property entirely, and add these delegate methods:

// Return the size for each cell
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let numberOfItemsPerRow: CGFloat = 3
    let interItemSpacing: CGFloat = 5
    let availableWidth = collectionView.bounds.width - (numberOfItemsPerRow - 1) * interItemSpacing
    let width = floor(availableWidth / numberOfItemsPerRow)
    return CGSize(width: width, height: width)
}

// Set inter-item spacing
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
    return 5
}

// Set line spacing (space between rows)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return 5
}

And update your setupCollectionView() to remove any flow layout setup (since the delegate will handle it):

private func setupCollectionView(){
    collectionView.delegate = self
    collectionView.dataSource = self
    let nib = UINib(nibName: "ItemCollectionViewCell", bundle: nil)
    collectionView.register(nib, forCellWithReuseIdentifier: cellIdentifier)
    
    // Optional: If you want to reset any default layout settings
    if let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        flowLayout.sectionInset = UIEdgeInsets.zero
        flowLayout.scrollDirection = .vertical
    }
}

Why These Work

  • Recalculating on every layout update: Ensures you're always using the latest collection view bounds, which is crucial if the view size changes (like rotation) or if the initial frame isn't final when viewWillLayoutSubviews first runs.
  • Flooring the width: Eliminates tiny fractional values that add up to make the total width exceed the collection view's bounds, which was likely pushing your third cell to the next row.

Either solution should fix that blank cell issue on smaller devices like the iPhone SE. Give them a try!

内容的提问来源于stack exchange,提问作者Part_Time_Nerd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:52:45