最新 SwiftUI API 参考
基于使用 Sosumi MCP 对 Apple 文档的比较,我们找到了推荐使用的最新 API。
本文件列出了什么是现代替代品。关于发现软废弃 API 时如何处理——何时迁移、何时保持不动、以及无关编辑的作用域规则——请参阅
references/soft-deprecation.md。要在新的 SDK 发布后刷新此列表,请运行.agents/skills/update-swiftui-apis/SKILL.md中的维护技能。
目录
- 始终使用(iOS 15+)
- 当目标是 iOS 16+
- 当目标是 iOS 17+
- 当目标是 iOS 18+
- 当目标是 iOS 26+
始终使用(iOS 15+)
这些 API 已被废弃足够久,没有理由再使用旧变体。
紧凑替代品
这些替代品的 API 形状变化最小。大多数是近乎直接的替换;少数需要额外的参数或结构调整:
navigationTitle(_:)代替navigationBarTitle(_:)toolbar { ToolbarItem(...) }代替navigationBarItems(...)(结构性变化)toolbarVisibility(.hidden, for: .navigationBar)代替navigationBarHidden(_:)statusBarHidden(_:)代替statusBar(hidden:)ignoresSafeArea(_:edges:)代替edgesIgnoringSafeArea(_:)preferredColorScheme(_:)代替colorScheme(_:)foregroundStyle(_:)代替foregroundColor(_:)(例如.foregroundStyle(.primary))clipShape(.rect(cornerRadius:))代替cornerRadius()textInputAutocapitalization(_:)代替autocapitalization(_:)(注意:.never取代.none)animation(_:value:)代替animation(_:)(增加必需的value:参数;向后部署到 iOS 13+)
列表与表单
使用尾随闭包Section初始化器,而不是位置参数的 header/footer View 初始化器。
单一标题形式仍然是当前用法,不应视为已废弃:
// 当前 - 单一标题 LocalizedStringKey 初始化器Section("Settings"){Toggle("Notifications",isOn:.constant(true))}// 替代 - content/header/footer 尾随闭包初始化器Section{Toggle("Notifications",isOn:.constant(true))}header:{Text("Settings")}footer:{Text("Changes apply immediately.")}// 已废弃/重命名 - 位置参数 header/footer View 参数Section(header:Text("Settings"),footer:Text("Changes apply immediately.")){Toggle("Notifications",isOn:.constant(true))}Section(header:Text("Settings")){Toggle("Notifications",isOn:.constant(true))}Section(footer:Text("Changes apply immediately.")){Toggle("Notifications",isOn:.constant(true))}呈现
- 始终使用
.confirmationDialog(_:isPresented:actions:message:)代替actionSheet(...)。 - 始终使用
.alert(_:isPresented:actions:message:)代替alert(isPresented:content:)。
两者都接受标题String、isPresented: Binding<Bool>、带Button项(支持role: .destructive/.cancel)的actions构建器,以及可选的message构建器:
.alert("Delete Item?",isPresented:$showAlert){Button("Delete",role:.destructive){deleteItem()}Button("Cancel",role:.cancel){}}message:{Text("This action cannot be undone.")}文本输入
始终使用onSubmit(of:_:)和focused(_:equals:)代替TextField的onEditingChanged/onCommit回调。
@FocusStateprivatevarisFocused:BoolTextField("Search",text:$query).focused($isFocused).onSubmit{performSearch()}无障碍
始终使用专门的无障碍修饰符,而不是通用的accessibility(...)变体。使用.accessibilityLabel()、.accessibilityValue()、.accessibilityHint()、.accessibilityAddTraits()、.accessibilityHidden()代替.accessibility(label:)、.accessibility(value:)等。
自定义环境/容器值
始终使用@Entry宏,而不是手动实现EnvironmentKey。@Entry宏在 Xcode 16 中引入,并向后部署到所有 OS 版本。
// 现代 — 一行取代约 10 行 EnvironmentKey 样板代码extensionEnvironmentValues{@EntryvarmyCustomValue:String="Default value"}样式
始终使用Button而不是onTapGesture(),除非你需要点击位置或次数。
Button("Tap me"){performAction()}// 仅当你需要位置或次数时才使用 onTapGestureImage("photo").onTapGesture(count:2){handleDoubleTap()}当目标是 iOS 16+
导航
使用NavigationStack(或NavigationSplitView)代替NavigationView。基于值的NavigationLink(value:)搭配.navigationDestination(for:)取代基于目的地的链接。
NavigationStack{List(items){iteminNavigationLink(value:item){Text(item.name)}}.navigationDestination(for:Item.self){DetailView(item:$0)}}简单重命名
tint(_:)代替accentColor(_:)autocorrectionDisabled(_:)代替disableAutocorrection(_:)
剪贴板
对于用户发起的粘贴 UI,优先使用PasteButton以避免粘贴提示。它会自动处理权限。仅当你需要编程式或非Transferable的剪贴板访问时才使用UIPasteboard(这会触发粘贴权限提示)。
PasteButton(payloadType:String.self){stringsinpastedText=strings.first??""}当目标是 iOS 17+
状态管理
- 新代码优先使用
@Observable而不是ObservableObject。使用@State代替@StateObject;使用@Bindable代替@ObservedObject。完整的@Observable迁移模式请参阅state-management.md。
事件
使用onChange(of:initial:_:)或onChange(of:) { }代替onChange(of:perform:)。
已废弃的变体只传递新值。现代变体提供旧值和新值两者,或无参数闭包。
- 无参数(最常见):
.onChange(of: value) { doSomething() } - 旧值和新值:
.onChange(of: value) { old, new in ... } - 带初始触发:
.onChange(of: value, initial: true) { ... } - 已废弃:
.onChange(of: value) { newValue in ... }—— 单参数闭包
感官反馈
在 SwiftUI 视图中,优先使用sensoryFeedback(_:trigger:)及相关重载,而不是UIImpactFeedbackGenerator、UISelectionFeedbackGenerator和UINotificationFeedbackGenerator。
以声明方式将触觉反馈附加到拥有状态变化的视图上,而不是在按钮动作中以命令式方式触发 UIKit 生成器。
@StateprivatevarisFavorite=falseButton("Favorite",systemImage:isFavorite?"heart.fill":"heart"){isFavorite.toggle()}.sensoryFeedback(.selection,trigger:isFavorite)当反馈只应在特定状态转换时触发,使用条件重载:
.sensoryFeedback(.selection,trigger:phase){old,newinold==.inactive||new==.expanded}手势
MagnifyGesture代替MagnificationGesture(通过value.magnification访问缩放量)RotateGesture代替RotationGesture(通过value.rotation访问角度)
布局
考虑使用containerRelativeFrame()或visualEffect()作为GeometryReader在尺寸和基于位置的效果方面的替代方案。GeometryReader没有被废弃,并且对于许多基于测量的布局仍然是必需的。
Image("hero").resizable().containerRelativeFrame(.horizontal){length,axisinlength*0.8}visualEffect { content, geometry in ... }—— 无需GeometryReader包装的基于位置的效果(视差、偏移)。onGeometryChange(for:of:action:)—— 响应特定视图的几何变化;对驱动状态/效果很有用。当布局本身依赖几何信息时,GeometryReader仍然更好。注意双闭包形式:.onGeometryChange(for:CGFloat.self){proxyinproxy.size.height}action:{newHeightinheight=newHeight}.coordinateSpace(.named("scroll"))代替.coordinateSpace(name: "scroll")。
当目标是 iOS 18+
标签页
使用TabAPI 代替tabItem(_:)。
TabView{Tab("Home",systemImage:"house"){HomeView()}Tab("Search",systemImage:"magnifyingglass"){SearchView()}Tab("Profile",systemImage:"person"){ProfileView()}}当使用Tab(role:)时,所有标签页都必须使用Tab语法。将Tab(role:)与.tabItem()混用会导致编译错误。
预览
在预览中为动态属性使用@Previewable。
// 现代(iOS 18+)#Preview{@Previewable@StatevarisOn=falseToggle("Setting",isOn:$isOn)}当目标是 iOS 26+
关于 Liquid Glass API(glassEffect、GlassEffectContainer、玻璃按钮样式),请参阅 liquid-glass.md。
滚动边缘效果
使用scrollEdgeEffectStyle(_:for:)配置滚动边缘行为。
ScrollView{// content}.scrollEdgeEffectStyle(.soft,for:.top)背景扩展
使用backgroundExtensionEffect()实现边缘延伸的模糊背景。
Liquid Glass 侧边栏后面的视图可能出现被裁剪的情况。这个修饰符会镜像并模糊安全区之外的内容,使插画保持可见。
Image("hero").backgroundExtensionEffect()来源:“Build a SwiftUI app with the new design”(WWDC25,会话 323)
标签栏
使用tabBarMinimizeBehavior(_:)控制标签栏在滚动时的最小化。
TabView{// tabs}.tabBarMinimizeBehavior(.onScrollDown)使用tabViewBottomAccessory在标签栏上方放置持久控件。从环境中读取tabViewBottomAccessoryPlacement,以便在辅助项折叠进标签栏区域时调整内容。
TabView{// tabs}.tabViewBottomAccessory{NowPlayingBar()}使用Tab(role: .search)创建专用的搜索标签页。该标签页会与其他标签页分离,并在选中时变形成搜索字段。
TabView{Tab("Home",systemImage:"house"){HomeView()}Tab("Profile",systemImage:"person"){ProfileView()}Tab(role:.search){SearchResultsView()}}来源:“What’s new in SwiftUI”(WWDC25,会话 256)和 “Build a SwiftUI app with the new design”(WWDC25,会话 323)
工具栏
使用ToolbarSpacer控制工具栏项的编组。固定间距在视觉上分隔相关组;弹性间距将项推开。
.toolbar{ToolbarItem(placement:.topBarTrailing){Button("Up",systemImage:"chevron.up"){}}ToolbarItem(placement:.topBarTrailing){Button("Down",systemImage:"chevron.down"){}}ToolbarSpacer(.fixed)ToolbarItem(placement:.topBarTrailing){Button("Settings",systemImage:"gear"){}}}使用sharedBackgroundVisibility(.hidden)从单个工具栏项移除玻璃组背景。
ToolbarItem(placement:.topBarTrailing){Image(systemName:"person.circle.fill").sharedBackgroundVisibility(.hidden)}在工具栏项内容上使用badge(_:)显示指示器。
ToolbarItem(placement:.topBarTrailing){Button("Notifications",systemImage:"bell"){}.badge(unreadCount)}来源:“Build a SwiftUI app with the new design”(WWDC25,会话 323)
搜索
使用searchToolbarBehavior(.minimizable)选择使用最小化的搜索按钮。系统可能会根据可用空间自动将搜索最小化为工具栏按钮。使用此修饰符显式选择启用。
NavigationStack{ContentView().searchable(text:$query).searchToolbarBehavior(.minimizable)}来源:“Build a SwiftUI app with the new design”(WWDC25,会话 323)
动画
使用@Animatable宏代替手动animatableData声明。该宏从所有可动画属性自动合成animatableData。使用@AnimatableIgnored排除特定属性。
@AnimatablestructWedge:Shape{varstartAngle:AnglevarendAngle:Angle@AnimatableIgnoredvardrawClockwise:Boolfuncpath(inrect:CGRect)->Path{/* ... */}}来源:“What’s new in SwiftUI”(WWDC25,会话 256)
呈现
使用navigationZoomTransition让 sheet 从其来源视图变形出现。工具栏项和按钮可以作为过渡来源。
.toolbar{ToolbarItem{Button("Add",systemImage:"plus"){showSheet=true}.navigationTransitionSource(id:"addSheet",namespace:namespace)}}.sheet(isPresented:$showSheet){AddItemView().navigationTransitionDestination(id:"addSheet",namespace:namespace)}来源:“Build a SwiftUI app with the new design”(WWDC25,会话 323)
控件
使用controlSize(.extraLarge)制作超大号的突出操作按钮。
Button("Get Started"){}.buttonStyle(.borderedProminent).controlSize(.extraLarge)对需要与容器边角匹配的按钮使用concentric边角样式。
Button("Confirm"){}.clipShape(.rect(cornerRadius:12,style:.concentric))Slider 现在支持刻度标记和中性值。
Slider(value:$speed,in:0.5...2.0,step:0.25){Text("Speed")}ticks:{SliderTick(value:0.6)SliderTick(value:0.9)}.sliderNeutralValue(1.0)来源:“Build a SwiftUI app with the new design”(WWDC25,会话 323)
富文本
使用带AttributedString绑定的TextEditor进行富文本编辑。支持粗体、斜体、下划线、删除线、自定义字体、前景/背景颜色、段落样式和 Genmoji。
@Stateprivatevartext:AttributedString="Hello, world!"varbody:someView{TextEditor(text:$text)}来源:“Cook up a rich text experience in SwiftUI with AttributedString”(WWDC25,会话 280)
网页内容
使用WebView显示网页内容。对于更丰富的交互,创建一个可观察的WebPage模型。
// 简单的 URL 显示WebView(url:URL(string:"https://example.com")!)// 带可观察模型@Stateprivatevarpage=WebPage()WebView(page).onAppear{page.load(URLRequest(url:myURL))}.navigationTitle(page.title??"")来源:“Meet WebKit for SwiftUI”(WWDC25,会话 231)
拖放
使用dragContainer进行多项目拖放操作。结合DragConfiguration实现自定义拖放行为,结合onDragSessionUpdated观察事件。
PhotoGrid(photos:photos).dragContainer(for:Photo.self){selectioninreturnselection.map{$0.transferable}}.onDragSessionUpdated{sessioninifsession.phase==.endedWithDelete{deleteSelectedPhotos()}}来源:“What’s new in SwiftUI”(WWDC25,会话 256)
场景桥接
UIKit 和 AppKit 生命周期应用现在可以请求 SwiftUI 场景。这使得命令式生命周期应用可以通过UIApplication.shared.activateSceneSession(for:errorHandler:)使用仅 SwiftUI 的场景类型,如MenuBarExtra和ImmersiveSpace。
来源:“What’s new in SwiftUI”(WWDC25,会话 256)
快速查找表
| 已废弃 | 推荐 | 起始版本 |
|---|---|---|
navigationBarTitle(_:) | navigationTitle(_:) | iOS 15+ |
navigationBarItems(...) | toolbar { ToolbarItem(...) } | iOS 15+ |
navigationBarHidden(_:) | toolbarVisibility(.hidden, for: .navigationBar) | iOS 15+ |
statusBar(hidden:) | statusBarHidden(_:) | iOS 15+ |
edgesIgnoringSafeArea(_:) | ignoresSafeArea(_:edges:) | iOS 15+ |
colorScheme(_:) | preferredColorScheme(_:) | iOS 15+ |
foregroundColor(_:) | foregroundStyle(_:) | iOS 15+ |
cornerRadius(_:) | clipShape(.rect(cornerRadius:)) | iOS 15+ |
actionSheet(...) | confirmationDialog(...) | iOS 15+ |
alert(isPresented:content:) | alert(_:isPresented:actions:message:) | iOS 15+ |
autocapitalization(_:) | textInputAutocapitalization(_:) | iOS 15+ |
accessibility(label:)等 | accessibilityLabel()等 | iOS 15+ |
TextFieldonCommit/onEditingChanged | onSubmit+focused | iOS 15+ |
animation(_:)(无 value) | animation(_:value:) | 向后部署(iOS 13+) |
Section(header:content:) | Section(content:header:) | 未来废弃 |
Section(footer:content:) | Section(content:footer:) | 未来废弃 |
Section(header:footer:content:) | Section(content:header:footer:) | 未来废弃 |
手动EnvironmentKey | @Entry宏 | 向后部署(Xcode 16+) |
NavigationView | NavigationStack/NavigationSplitView | iOS 16+ |
accentColor(_:) | tint(_:) | iOS 16+ |
disableAutocorrection(_:) | autocorrectionDisabled(_:) | iOS 16+ |
UIPasteboard.general | PasteButton | iOS 16+ |
onChange(of:perform:) | onChange(of:) { }或onChange(of:) { old, new in } | iOS 17+ |
UIImpactFeedbackGenerator/UISelectionFeedbackGenerator/UINotificationFeedbackGenerator | sensoryFeedback(_:trigger:) | iOS 17+ |
MagnificationGesture | MagnifyGesture | iOS 17+ |
RotationGesture | RotateGesture | iOS 17+ |
coordinateSpace(name:) | coordinateSpace(.named(...)) | iOS 17+ |
ObservableObject | @Observable | iOS 17+ |
tabItem(_:) | TabAPI | iOS 18+ |
手动animatableData | @Animatable宏 | iOS 26+ |
sheet 上的presentationBackground(_:) | 默认 Liquid Glass sheet 材质 | iOS 26+ |
| 自定义工具栏背景 hack | scrollEdgeEffectStyle(_:for:) | iOS 26+ |