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

iOS Swift4 纯代码实现UIScrollView无法正常滚动问题求助

UIScrollView滚动异常问题修复方案

现存错误点

  • 重复添加scrollView到父视图:代码中两次调用self.view.addSubview(scrollView),属于冗余操作,可能引发图层层级异常。
  • 高度计算逻辑完全错误:
    1. 循环遍历self.scrollView.subviews时,累加的是当前控制器根视图view的高度,而非遍历到的子视图高度,完全拿不到正确的子视图高度总和。
    2. 实际需要累加的是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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 17:24:03