Swift4中动态添加UIScrollView及滚动失效问题求助
一、先解决你遇到的滚动失效问题
UIScrollView不能滚动,大概率是contentSize设置不正确或者约束逻辑有问题,这是Swift4里很常见的坑,给你梳理几个核心排查点:
- 确保contentSize大于ScrollView自身尺寸
UIScrollView的滚动前提是它的contentSize(内容区域大小)要比自身的bounds大。如果你的子视图是动态变化的(比如TextView内容更新、图片加载完成),必须在内容变化后重新计算并设置contentSize:
// 假设你把所有子视图都放在一个叫contentView的容器里 scrollView.contentSize = contentView.frame.size
如果用Auto Layout管理布局,更推荐让系统自动计算contentSize:给contentView设置和scrollView的contentLayoutGuide完全对齐的约束,同时让contentView的宽度等于scrollView的frameLayoutGuide宽度(避免不必要的水平滚动),这样只要contentView的子视图约束能撑满它,scrollView就会自动获取正确的contentSize。
检查子视图的约束逻辑
比如你的TextView如果开启了滚动(isScrollEnabled = true),它的高度会固定,无法根据内容撑开contentView,导致contentView高度不够,scrollView自然没法滚动。记得把TextView的isScrollEnabled设为false,让它自动适应内容高度。关闭自动调整Insets的干扰
Swift4的ViewController默认会自动调整scrollView的insets来适配导航栏、状态栏,这可能导致布局计算混乱。你可以在ViewController里关闭这个特性:
automaticallyAdjustsScrollViewInsets = false
或者在Storyboard里找到ViewController的属性面板,取消勾选"Adjust Scroll View Insets"选项。
二、Swift4中动态添加UIScrollView的标准流程
手动代码创建UIScrollView的话,推荐用容器视图+Auto Layout的方式,比直接设置frame更灵活,也能避免动态内容的适配问题:
- 创建并添加ScrollView到父视图
let scrollView = UIScrollView() scrollView.translatesAutoresizingMaskIntoConstraints = false // 必须关闭自动转换约束 scrollView.showsVerticalScrollIndicator = true scrollView.showsHorizontalScrollIndicator = false view.addSubview(scrollView)
- 创建内容容器视图(关键!)
把所有子视图(图片、TextView、按钮)放在一个contentView里,再把contentView加到scrollView上,这样约束管理会清晰很多:
let contentView = UIView() contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView)
- 设置ScrollView和ContentView的约束
用Auto Layout绑定它们的位置关系,确保scrollView占满父视图,contentView能正确撑开scrollView的contentSize:
// 绑定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) ]) // 绑定contentView到scrollView的contentLayoutGuide,同时宽度和父视图一致 NSLayoutConstraint.activate([ contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor), contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor), contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor), contentView.widthAnchor.constraint(equalTo: view.widthAnchor) ])
- 添加子视图到ContentView并设置约束
比如添加动态高度的TextView和按钮:
// 添加TextView let textView = UITextView() textView.translatesAutoresizingMaskIntoConstraints = false textView.isScrollEnabled = false // 必须关闭,让它自动适应内容高度 textView.text = "这里是会动态变化的文本内容..." contentView.addSubview(textView) // 添加按钮 let actionButton = UIButton(type: .system) actionButton.translatesAutoresizingMaskIntoConstraints = false actionButton.setTitle("点击按钮", for: .normal) contentView.addSubview(actionButton) // 设置子视图约束,确保内容能撑开contentView NSLayoutConstraint.activate([ // TextView的约束 textView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20), textView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20), textView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20), // 按钮的约束,和TextView底部对齐,底部留间距 actionButton.topAnchor.constraint(equalTo: textView.bottomAnchor, constant: 30), actionButton.centerXAnchor.constraint(equalTo: contentView.centerXAnchor), actionButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20) ])
这样设置后,当TextView的内容变化时,它的高度会自动调整,contentView的高度也会跟着变化,scrollView就能正常滚动了。
内容的提问来源于stack exchange,提问作者lakshmi sravya Gajavalli

