如果你写过 SwiftUI,一定很熟悉实时预览:改代码画布立刻看到界面效果,不用跑模拟器。 但以前写 UIKit 是非常痛苦的,每次修改控件都要启动模拟器编译运行才能看效果。
Xcode15 + iOS17,苹果正式推出 UIKit Previews。可以直接在 Xcode 画布预览 UIKit 的 View、ViewController,不用启动模拟器 / 真机运行 App,对 UIKit 项目来说是巨大提升。
用法和 SwiftUI 预览几乎一样,用#Preview宏把UIView或者UIViewController包起来即可。
各个使用场景、代码、坑点详解
#Preview是 Swift 宏;@available(iOS 17, *)必须加,低于 iOS17 系统没有这个能力。
场景 1:预览普通控件(UILabel / UIButton)
import UIKit
class ViewController: UIViewController {
// 创建一个红色label
func makeLabel() -> UILabel {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
label.backgroundColor = .red
label.text = "Hello, World!"
label.textAlignment = .center
return label
}
}
// MARK: - UIKit预览代码
@available(iOS 17, *)
#Preview {
// 直接返回要预览的UIView对象
ViewController().makeLabel()
}
做了什么:
makeLabel()构造 UILabel 实例。#Preview { }闭包里面返回 UIView,Xcode 右侧画布就渲染出这个控件。- 修改代码,画布实时刷新,不需要启动模拟器。
⚠️注意:
ViewController()只是临时实例,不会执行 App 完整启动流程,只是单纯渲染 UI。
场景 2:预览自定义 UIView(最常用!业务自定义组件)
写自定义CustomView,比如自定义按钮、卡片、cell 内部 view,直接预览组件效果。
import UIKit
class CustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() {
backgroundColor = .blue
let label = UILabel()
label.text = "UIKit Previews! 🚀"
label.textColor = .white
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: centerXAnchor),
label.centerYAnchor.constraint(equalTo: centerYAnchor)
])
}
}
// 预览自定义View
@available(iOS 17, *)
#Preview {
// 指定宽高frame,画布就按这个尺寸渲染组件
CustomView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
}
✅业务场景 写自定义卡片、输入框、Cell 的 contentView、弹窗组件时,写完立刻看样式,不用把页面 push 出来看。
场景 3:预览整个 UIViewController(整个页面预览)
可以直接预览完整控制器,整个页面渲染在画布。
import UIKit
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
}
}
// 预览控制器
@available(iOS 17, *)
#Preview {
MyViewController()
}
内部会自动读取 vc 的
view进行渲染。
进阶扩展(原文没有,实际开发高频用法)
① 多设备预览,同时看手机、平板
@available(iOS 17, *)
#Preview("手机", traits: .init(width: 393, height: 852)) {
MyViewController()
}
#Preview("平板", traits: .init(width: 1024, height: 768)) {
MyViewController()
}
② 预览带导航栏的页面(UINavigationController 嵌套)
很多页面依赖导航栏,直接预览 vc 看不到导航栏效果,包一层导航控制器:
@available(iOS 17, *)
#Preview {
UINavigationController(rootViewController: MyViewController())
}
③ 预览 UITableViewCell
cell 预览,不用跑模拟器进列表:
class DemoCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
textLabel?.text = "测试Cell"
}
required init?(coder: NSCoder) { fatalError("") }
}
@available(iOS 17, *)
#Preview {
DemoCell(style: .default, reuseIdentifier: nil)
}
UIKit Previews 核心优点
- 不用等待模拟器启动编译,改 UI 立刻看效果;
- 自定义 View、Cell、ViewController 快速调样式;
- 和 SwiftUI 预览画布是同一个。
⚠️重点坑(官方文档没有,踩坑必看)
- 最低版本限制:iOS17 / Xcode15 项目 Deployment Target 如果低于 iOS17,必须加
@available(iOS 17, *)包裹#Preview,否则编译报错。
这个预览只是开发期工具,
#Preview代码打包 App 的时候会自动剥离,不会打进安装包。
- 预览环境 ≠ 真实 App 运行环境
- SceneDelegate、AppDelegate不会执行;
- 网络请求、数据库、通知、单例逻辑不会完整走;
- 适合只看 UI 布局样式;不要依赖业务逻辑执行。
如果你的控件强依赖网络数据、全局状态,预览会显示空白或者报错。可以给预览做模拟假数据。
- AutoLayout 约束报错: 自定义 View 如果没给 frame,或者约束缺少,画布会报布局警告,和模拟器报错行为一致。
- 不能预览 iOS16 及以下设备,是 Xcode 开发工具能力,不是运行时能力。
什么时候适合用 / 不适合用
✅适合
- 自定义 UI 组件、卡片、按钮、Cell 布局调样式;
- 静态页面 UI 调试;
- 快速查看颜色、圆角、约束效果。
❌不适合
- 强依赖网络、登录状态、数据库的复杂业务页面;
- 需要测试点击交互、跳转逻辑(预览不能真正点击交互,只是看静态 UI)。
和 SwiftUI Preview 简单对比
表格
| SwiftUI Preview | UIKit Previews(#Preview) | |
|---|---|---|
| 最低版本 | Xcode11+ | Xcode15 + iOS17+ |
| 返回内容 | SwiftUI View | UIView / UIViewController |
| 交互 | 可以简单交互 | 静态预览,不能真正点击 |
| 打包行为 | 自动剥离 | 自动剥离 |