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

如何在Swift中通过代码实现类似In-shorts的垂直滚动效果(无Storyboard)

实现类似In-shorts的垂直滚动视图(纯Swift代码)

当然可以用UIScrollView实现这个效果!甚至不需要第三方库就能搞定,纯原生Swift代码就能复刻In-shorts那种顺滑的上滑切换视图体验。下面我给你拆解核心思路,再附上完整的可运行代码示例,还有可选的第三方库推荐~

核心思路

In-shorts的核心体验是上滑切换全屏视图,松手后自动吸附到当前视图顶部,用UIScrollView完全可以实现:

  1. 把每个要展示的内容视图设置为全屏尺寸,依次垂直排列在ScrollView里
  2. 将ScrollView的contentSize设置为所有内容视图的高度总和(通过Auto Layout自动约束即可实现,无需手动计算)
  3. 监听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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:13:30