如何在Swift中通过代码实现类似In-shorts的垂直滚动效果(无Storyboard)
实现类似In-shorts的垂直滚动视图(纯Swift代码)
当然可以用UIScrollView实现这个效果!甚至不需要第三方库就能搞定,纯原生Swift代码就能复刻In-shorts那种顺滑的上滑切换视图体验。下面我给你拆解核心思路,再附上完整的可运行代码示例,还有可选的第三方库推荐~
核心思路
In-shorts的核心体验是上滑切换全屏视图,松手后自动吸附到当前视图顶部,用UIScrollView完全可以实现:
- 把每个要展示的内容视图设置为全屏尺寸,依次垂直排列在ScrollView里
- 将ScrollView的
contentSize设置为所有内容视图的高度总和(通过Auto Layout自动约束即可实现,无需手动计算) - 监听ScrollView的滚动结束事件,根据滚动位置和速度,自动将ScrollView偏移到最近的视图顶部,实现吸附效果
纯Swift代码实现步骤
下面是完整的ViewController代码,直接复制就能运行:
import UIKit class VerticalScrollViewController: UIViewController, UIScrollViewDelegate { private let scrollView = UIScrollView() // 存储所有内容视图,方便后续计算滚动位置 private var contentViews = [UIView]() override func viewDidLoad() { super.viewDidLoad() setupScrollViewConstraints() createContentViews() } private func setupScrollViewConstraints() { view.addSubview(scrollView) scrollView.translatesAutoresizingMaskIntoConstraints = false scrollView.delegate = self // 配置ScrollView基础属性:禁止水平滚动、隐藏滚动指示器 scrollView.isPagingEnabled = false scrollView.showsVerticalScrollIndicator = 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) ]) } private func createContentViews() { // 模拟3个全屏内容视图,你可以替换成自己的自定义视图 let viewColors: [UIColor] = [.systemBlue, .systemGreen, .systemOrange] var previousContentView: UIView? for color in viewColors { let contentView = UIView() contentView.backgroundColor = color contentView.translatesAutoresizingMaskIntoConstraints = false scrollView.addSubview(contentView) // 设置每个内容视图为全屏尺寸 NSLayoutConstraint.activate([ contentView.widthAnchor.constraint(equalTo: scrollView.widthAnchor), contentView.heightAnchor.constraint(equalTo: scrollView.heightAnchor), contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor), contentView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor) ]) // 垂直排列视图:第一个视图顶部对齐ScrollView,后续视图顶部对齐上一个视图的底部 if let prevView = previousContentView { contentView.topAnchor.constraint(equalTo: prevView.bottomAnchor).isActive = true } else { contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true } // 最后一个视图底部对齐ScrollView,自动撑开contentSize if color == viewColors.last { contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true } contentViews.append(contentView) previousContentView = contentView } } // 实现滚动吸附逻辑:滚动结束时自动停在最近的视图顶部 func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { let screenHeight = view.bounds.height let currentOffsetY = scrollView.contentOffset.y // 计算当前偏移对应的视图索引 var targetIndex = Int(currentOffsetY / screenHeight) // 根据滚动速度调整目标索引:上滑速度快则跳到下一个,下滑快则跳到上一个 if velocity.y > 0.5 { targetIndex += 1 } else if velocity.y < -0.5 { targetIndex -= 1 } // 确保索引在合法范围内,避免越界 targetIndex = max(0, min(targetIndex, contentViews.count - 1)) // 设置最终偏移量,让ScrollView精准停在目标视图顶部 targetContentOffset.pointee.y = CGFloat(targetIndex) * screenHeight } }
代码关键点说明
- 每个内容视图通过Auto Layout绑定为全屏尺寸,无需手动计算屏幕大小
- ScrollView的
contentSize由最后一个视图的底部约束自动撑开,无需手动设置 scrollViewWillEndDragging方法是实现吸附效果的核心,通过滚动速度和当前位置判断用户意图,自动对齐视图
第三方库推荐(可选)
如果不想自己写滚动逻辑,也可以用成熟的第三方库简化开发:
- Parchment:原本是分页标题栏库,但支持垂直分页滚动,配置灵活,适合复杂场景
- SwiftPages:轻量级的分页滚动库,支持垂直方向,集成简单
不过原生UIScrollView的方案已经足够轻量、无依赖,完全能满足你的需求,更推荐优先使用原生实现。
内容的提问来源于stack exchange,提问作者Sanjana Nanjappa
相关产品推荐
相关产品推荐

