iOS Swift4 纯代码实现UIScrollView无法正常滚动问题求助
UIScrollView滚动异常问题修复方案
现存错误点
- 重复添加scrollView到父视图:代码中两次调用
self.view.addSubview(scrollView),属于冗余操作,可能引发图层层级异常。 - 高度计算逻辑完全错误:
- 循环遍历
self.scrollView.subviews时,累加的是当前控制器根视图view的高度,而非遍历到的子视图高度,完全拿不到正确的子视图高度总和。 - 实际需要累加的是
contentView内部的子视图(imagesScrollView、view1~view4)的高度+各视图之间的垂直间距,而非scrollView的子视图高度,scrollView的直接子视图只有contentView,遍历它根本拿不到内部内容高度。
- 循环遍历
- contentSize设置时机错误:在
setupMainView中执行高度计算时,所有子视图的frame可能还未完成最终布局,拿到的高度值不准确,导致最终contentSize不符合预期。 - 冗余无效代码:
scrollView.reloadInputViews()是用于刷新自定义输入视图的方法,对scrollView滚动范围设置完全无效,属于冗余代码。
修复方案
方案1:手写frame布局适配(适配iOS10+)
func setupMainView() { // 1. 先初始化所有内部子视图,确保所有子视图的frame已经正确赋值 self.setupImagesView() self.setupView1() self.setupView2() self.setupView3() self.setupView4() // 2. 初始化scrollView,仅添加一次到父视图 self.scrollView = UIScrollView() self.scrollView.backgroundColor = .white self.scrollView.contentInset = .zero self.scrollView.scrollIndicatorInsets = .zero self.automaticallyAdjustsScrollViewInsets = false // 给scrollView设置正确的frame,比如撑满当前控制器视图 self.scrollView.frame = self.view.bounds self.scrollView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.view.addSubview(self.scrollView) // 3. 初始化contentView self.contentView = UIView() self.scrollView.addSubview(contentView) // 4. 把所有内容视图添加到contentView,确保它们的frame已经设置好,包含垂直间距 contentView.addSubview(imagesScrollView) contentView.addSubview(view1) contentView.addSubview(view2) contentView.addSubview(view3) contentView.addSubview(view4) // 5. 正确计算contentView总高度,按你的布局逻辑累加视图高度+垂直间距 var totalHeight: CGFloat = 0.0 // 按你的实际布局顺序累加,比如先加轮播图高度,再加第一个视图的高度+间距,以此类推 totalHeight += imagesScrollView.frame.height totalHeight += 10 // 假设轮播图和view1的间距是10,可按需调整 totalHeight += view1.frame.height totalHeight += 10 // view1和view2的间距,可按需调整 totalHeight += view2.frame.height totalHeight += 10 // view2和view3的间距,可按需调整 totalHeight += view3.frame.height totalHeight += 10 // view3和view4的间距,可按需调整 totalHeight += view4.frame.height totalHeight += 20 // 底部安全间距,可按需调整 // 6. 设置contentView和contentSize contentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: totalHeight) scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: totalHeight) }
如果存在横竖屏切换需求,需要在viewDidLayoutSubviews中重新更新scrollView的frame和contentSize值。
方案2:AutoLayout适配(推荐,适配iOS10+,无需手动计算contentSize)
func setupMainView() { self.setupImagesView() self.setupView1() self.setupView2() self.setupView3() self.setupView4() self.scrollView = UIScrollView() self.scrollView.backgroundColor = .white self.scrollView.translatesAutoresizingMaskIntoConstraints = false self.view.addSubview(self.scrollView) self.automaticallyAdjustsScrollViewInsets = false // scrollView约束撑满父视图 NSLayoutConstraint.activate([ scrollView.topAnchor.constraint(equalTo: view.topAnchor), scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) self.contentView = UIView() contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView) // contentView绑定到scrollView的contentLayoutGuide let contentGuide = scrollView.contentLayoutGuide let frameGuide = scrollView.frameLayoutGuide NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: contentGuide.topAnchor), contentView.leadingAnchor.constraint(equalTo: contentGuide.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: contentGuide.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: contentGuide.bottomAnchor), contentView.widthAnchor.constraint(equalTo: frameGuide.widthAnchor) ]) // 添加所有子视图到contentView,子视图的translatesAutoresizingMaskIntoConstraints设为false contentView.addSubview(imagesScrollView) contentView.addSubview(view1) contentView.addSubview(view2) contentView.addSubview(view3) contentView.addSubview(view4) // 以下为示例子视图约束,按你的实际布局调整,最后一个视图的bottomAnchor绑定到contentView的bottomAnchor即可,系统会自动计算contentSize NSLayoutConstraint.activate([ imagesScrollView.topAnchor.constraint(equalTo: contentView.topAnchor), imagesScrollView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), imagesScrollView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), imagesScrollView.heightAnchor.constraint(equalToConstant: 200), view1.topAnchor.constraint(equalTo: imagesScrollView.bottomAnchor, constant: 10), view1.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), view1.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), view1.heightAnchor.constraint(equalToConstant: 100), // 剩余view2~view4依次设置垂直约束 view4.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20) ]) }
内容的提问来源于stack exchange,提问作者user1300830
相关产品推荐
相关产品推荐

