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
相关产品推荐
相关产品推荐

