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

Swift实现TableView滚动时动态调整UICollectionView与TableView高度占比

Hey there! Let's tackle your problem step by step—you're dealing with screen jank when resizing your collection/table views, want a smoother progressive adjustment via pan gestures, plus a better way to handle collection view cell sizing. Here's how to fix this properly:

Solution: Progressive Height Adjustment + Performance Optimization

1. Ditch Constant Updates—Use Constraint Multipliers Instead

Your original setup uses equal-height constraints relative to the parent view, so modifying the multiplier of the collection view's height constraint is the right approach (not adjusting constants). This keeps your layout logic aligned with Auto Layout's intended behavior.

First, add an IBOutlet for your collection view's height constraint in MainScreenVC:

@IBOutlet weak var collectionViewHeightConstraint: NSLayoutConstraint!

2. Implement Pan Gesture for Smooth Progressive Resizing

Since the table view has its own scroll gesture, we need to make the pan gesture play nice with it. Here's how to set it up:

override func viewDidLoad() {
    super.viewDidLoad()
    // Add pan gesture to the table view
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
    panGesture.cancelsTouchesInView = false // Allow table view to receive touches too
    panGesture.delegate = self
    tableView.addGestureRecognizer(panGesture)
}

// Allow simultaneous recognition of pan and table view scroll gestures
extension MainScreenVC: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
    let translation = gesture.translation(in: view)
    let viewHeight = view.bounds.height
    
    // Define your target multipliers
    let defaultCollectionMultiplier: CGFloat = 1/3 // 1:2 split
    let minimizedCollectionMultiplier: CGFloat = 1/5 // 1:4 split
    let multiplierRange = defaultCollectionMultiplier - minimizedCollectionMultiplier
    
    var newMultiplier = collectionViewHeightConstraint.multiplier
    
    // Calculate new multiplier based on drag direction and distance
    if translation.y < 0 { // Upward drag: shrink collection view
        let dragFraction = min(-translation.y / (viewHeight * multiplierRange), 1.0)
        newMultiplier = defaultCollectionMultiplier - (multiplierRange * dragFraction)
    } else { // Downward drag: restore collection view
        let dragFraction = min(translation.y / (viewHeight * multiplierRange), 1.0)
        newMultiplier = minimizedCollectionMultiplier + (multiplierRange * dragFraction)
    }
    
    // Clamp multiplier to valid range
    newMultiplier = max(minimizedCollectionMultiplier, min(defaultCollectionMultiplier, newMultiplier))
    
    // Update constraint without animation for smooth live resizing
    collectionViewHeightConstraint.isActive = false
    collectionViewHeightConstraint = collectionView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: newMultiplier)
    collectionViewHeightConstraint.isActive = true
    view.layoutIfNeeded()
    
    // Optional: Auto-snap to nearest state when gesture ends
    if gesture.state == .ended || gesture.state == .cancelled {
        let targetMultiplier = newMultiplier < (defaultCollectionMultiplier + minimizedCollectionMultiplier)/2 ? minimizedCollectionMultiplier : defaultCollectionMultiplier
        UIView.animate(withDuration: 0.2) {
            self.collectionViewHeightConstraint.isActive = false
            self.collectionViewHeightConstraint = self.collectionView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: targetMultiplier)
            self.collectionViewHeightConstraint.isActive = true
            self.view.layoutIfNeeded()
        }
    }
}

3. Fix Cell Sizing to Eliminate Jank

Your original approach using notifications to update every cell's constraints is a big cause of lag. Instead, let the collection view's layout handle cell sizing automatically based on its current height:

class MainScreenVC: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
    private let flowLayout = UICollectionViewFlowLayout()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        collectionView.collectionViewLayout = flowLayout
        // Set your desired spacing
        flowLayout.minimumInteritemSpacing = 10
        flowLayout.minimumLineSpacing = 10
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        // Calculate cell size based on current collection view height
        let cellHeight = collectionView.bounds.height - 20 // Subtract padding if needed
        let cellWidth = cellHeight * 1.5 // Your aspect ratio
        flowLayout.itemSize = CGSize(width: cellWidth, height: cellHeight)
        // Invalidate layout to update cells immediately
        collectionView.collectionViewLayout.invalidateLayout()
    }
}

Now you can delete all the notification code in your cell class, along with the MyConstant global variable—you don't need them anymore!

4. Key Improvements Recap

  • Constraint Multipliers: Aligns with Auto Layout best practices for proportional sizing.
  • Pan Gesture Compatibility: Lets users drag to resize while still scrolling the table view.
  • Layout-Driven Cell Sizing: Avoids individual cell updates, eliminating lag.
  • Cleaner Code: Removes global state and unnecessary notifications for better maintainability.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:15:17