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

Swift 5 编程为UIScrollView添加网格按钮滚动失效如何解决

UIScrollView网格按钮滚动问题修复方案

问题根因

  • 层级与frame配置错误:你设置的scrollView起始y坐标为50,和上方label的位置完全重叠,后添加的scrollView层级更高,直接覆盖了label;同时scrollView高度设置为全屏高度,底部会延伸到屏幕可视区域之外
  • 未正确配置contentSize:你注释了contentSize的设置代码,即便解开注释,也建议contentSize的高度匹配内部控件实际占用的总高度,避免无效的空白滚动区域
  • 手动计算按钮frame本身不会影响滚动,只要contentSize的尺寸大于scrollView自身的可视尺寸,就可以正常滚动

修复后的frame版本代码

直接修改你现有代码的几处配置即可正常运行:

class ViewController: UIViewController {
    
    let label = UILabel(frame: CGRect(x: UIScreen.main.bounds.width/2 - 100, y: 50, width: 200, height: 200))
    // 修正scrollView的frame:起始y在label下方,高度为剩余屏幕高度
    let scrollView = UIScrollView(frame: CGRect(x: 0, y: 250, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 250))
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 禁用系统自动给scrollView添加的顶部内边距,避免偏移
        scrollView.contentInsetAdjustmentBehavior = .never
        
        self.view.addSubview(label)
        self.view.addSubview(scrollView)
        
        var idx = 1
        let totalRow = 21
        let buttonSize: CGFloat = 50
        let buttonTopOffset: CGFloat = 200
        for row in 0..<totalRow {
            for col in 0...4 {
                let button = UIButton(frame: CGRect(x: CGFloat(col)*buttonSize, y: CGFloat(row)*buttonSize + buttonTopOffset, width: buttonSize, height: buttonSize))
                button.backgroundColor = .gray
                button.setTitle("\(idx)", for: .normal)
                button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
                scrollView.addSubview(button)
                idx += 1
            }
        }
        // 计算所有内容总高度,赋值给contentSize
        let totalContentHeight = CGFloat(totalRow) * buttonSize + buttonTopOffset
        scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: totalContentHeight)
    }
    
    @objc func buttonAction(sender: UIButton!) {
        label.text = sender.title(for: .normal)
    }
}

更推荐的实现方案:UICollectionView

如果后续需要适配多尺寸屏幕、调整列数或者增加交互,用UICollectionView实现网格布局更省心,无需手动计算每个按钮的frame,自带滚动能力:

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    let label = UILabel(frame: CGRect(x: UIScreen.main.bounds.width/2 - 100, y: 50, width: 200, height: 200))
    var collectionView: UICollectionView!
    let totalCount = 105 // 5列*21行
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.addSubview(label)
        
        // 配置collectionView布局
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 50, height: 50)
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 0
        layout.sectionInset = .zero
        
        // 初始化collectionView
        collectionView = UICollectionView(frame: CGRect(x: 0, y: 250, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - 250), collectionViewLayout: layout)
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.backgroundColor = .white
        collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
        self.view.addSubview(collectionView)
    }
    
    // MARK: CollectionView DataSource
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return totalCount
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
        // 移除cell上旧的按钮避免复用问题
        cell.subviews.forEach { $0.removeFromSuperview() }
        
        let button = UIButton(frame: cell.bounds)
        button.backgroundColor = .gray
        button.setTitle("\(indexPath.row + 1)", for: .normal)
        button.addTarget(self, action: #selector(buttonAction(sender:)), for: .touchUpInside)
        cell.addSubview(button)
        return cell
    }
    
    @objc func buttonAction(sender: UIButton!) {
        label.text = sender.title(for: .normal)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 22:57:01