SwiftUI 常用控件分类与使用指南
目录
- 一、文本显示控件
- 1.1、Text - 基础文本
- 1.2、Label - 图标+文本组合
- 1.3、Link - 可点击链接
- 二、图片显示控件
- 2.1、Image - 图片显示
- 2.2、AsyncImage - 异步加载图片
- 三、按钮与交互控件
- 3.1、Button - 基础按钮
- 3.2、Menu - 下拉菜单
- 3.3、ContextMenu - 长按菜单
- 四、输入控件
- 4.1、TextField - 单行文本输入
- 4.1、TextEditor - 多行文本输入
- 4.3、SecureField - 密码输入
- 五、选择器控件
- 5.1、Toggle - 开关
- 5.2、Picker - 选择器
- 5.3、Slider - 滑块
- 5.4、Stepper - 步进器
- 5.5、DatePicker - 日期选择
- 六、列表与集合视图
- 6.1、List - 列表视图
- 6.2、ScrollView - 滚动视图
- 6.3、Grid - 网格布局 (iOS 16+)
- 七、进度指示器
- 7.1、ProgressView - 进度条
- 7.2、ActivityIndicator - 活动指示器 (UIKit桥接)
- 八、容器视图
- 8.1、VStack/HStack/ZStack - 基础布局
- 8.2、LazyVStack/LazyHStack - 懒加载布局
- 8.3、Group/GroupBox - 内容分组
- 九、导航相关
- 9.1、NavigationStack - 导航栈
- 9.2、TabView - 标签页
- 十、弹窗与提示
- 10.1、Alert - 警告框
- 10.2、Sheet - 底部表单
- 10.3、Toast - 提示 (自定义实现)
- 十一、形状与绘图
- 11.1、基础形状
- 11.2、自定义形状
- 十二、高级控件
- 12.1、Canvas - 绘图画布 (iOS 15+)
- 12.2、Charts - 图表框架 (iOS 16+)
- 最佳实践建议
- 1、组合使用:通过组合简单控件创建复杂UI
- 2、响应式设计:使用 `@ViewBuilder` 和条件语句
- 3、平台适配
- 4、性能优化
SwiftUI 提供了丰富的控件库,我将按功能分类介绍常用控件并提供使用示例:
一、文本显示控件
1.1、Text - 基础文本
Text("Hello SwiftUI!").font(.title) // 字体.foregroundStyle(.blue) // 颜色.bold() // 加粗.italic() // 斜体
1.2、Label - 图标+文本组合
Label("设置", systemImage: "gear").symbolRenderingMode(.multicolor) // 图标渲染模式Label("邮件", image: "custom_email") // 使用自定义图片
1.3、Link - 可点击链接
Link("访问苹果官网", destination: URL(string: "https://www.apple.com")!)
二、图片显示控件
2.1、Image - 图片显示
// 系统图标
Image(systemName: "heart.fill").resizable().aspectRatio(contentMode: .fit).frame(width: 50, height: 50).foregroundStyle(.red)// 资源图片
Image("profile_picture").resizable().scaledToFill().frame(width: 100, height: 100).clipShape(Circle()) // 圆形裁剪
2.2、AsyncImage - 异步加载图片
AsyncImage(url: URL(string: "https://example.com/image.jpg")) { image inimage.resizable()
} placeholder: {ProgressView()
}
.frame(width: 200, height: 200)
.clipShape(RoundedRectangle(cornerRadius: 10))
三、按钮与交互控件
3.1、Button - 基础按钮
Button("提交") {print("按钮被点击")
}
.buttonStyle(.borderedProminent)
.tint(.purple)
3.2、Menu - 下拉菜单
Menu("操作") {Button("复制", action: {})Button("粘贴", action: {})Menu("更多") {Button("保存", action: {})Button("删除", action: {})}
}
3.3、ContextMenu - 长按菜单
Image(systemName: "ellipsis.circle").contextMenu {Button("编辑", action: {})Button("分享", action: {})Button("删除", role: .destructive, action: {})}
四、输入控件
4.1、TextField - 单行文本输入
@State private var username = ""TextField("用户名", text: $username).textFieldStyle(.roundedBorder).autocorrectionDisabled() // 禁用自动修正.textInputAutocapitalization(.never) // 禁用首字母大写
4.1、TextEditor - 多行文本输入
@State private var bio = ""TextEditor(text: $bio).frame(height: 150).border(Color.gray, width: 1)
4.3、SecureField - 密码输入
@State private var password = ""SecureField("密码", text: $password).textFieldStyle(.roundedBorder)
五、选择器控件
5.1、Toggle - 开关
@State private var isOn = falseToggle("启用通知", isOn: $isOn).toggleStyle(.switch) // 开关样式.tint(.green) // 自定义颜色
5.2、Picker - 选择器
enum Flavor: String, CaseIterable {case chocolate, vanilla, strawberry
}@State private var selectedFlavor = Flavor.chocolatePicker("选择口味", selection: $selectedFlavor) {ForEach(Flavor.allCases, id: \.self) { flavor inText(flavor.rawValue.capitalized)}
}
.pickerStyle(.menu) // 菜单样式
5.3、Slider - 滑块
@State private var volume: Double = 50Slider(value: $volume,in: 0...100,step: 5,label: { Text("音量") },minimumValueLabel: { Text("0") },maximumValueLabel: { Text("100") }
)
5.4、Stepper - 步进器
@State private var quantity = 1Stepper("数量: \(quantity)", value: $quantity, in: 1...10)
5.5、DatePicker - 日期选择
@State private var date = Date()DatePicker("选择日期", selection: $date, displayedComponents: .date).datePickerStyle(.graphical) // 日历样式
六、列表与集合视图
6.1、List - 列表视图
struct Item: Identifiable {let id = UUID()let name: String
}let items = [Item(name: "苹果"), Item(name: "香蕉"), Item(name: "橙子")]List(items) { item inText(item.name)
}
.listStyle(.insetGrouped) // 分组样式
6.2、ScrollView - 滚动视图
ScrollView {LazyVStack { // 懒加载VStackForEach(1...100, id: \.self) { index inText("项目 \(index)").padding().frame(maxWidth: .infinity).background(index % 2 == 0 ? .blue.opacity(0.1) : .green.opacity(0.1))}}
}
6.3、Grid - 网格布局 (iOS 16+)
let columns = [GridItem(.adaptive(minimum: 100))]ScrollView {LazyVGrid(columns: columns, spacing: 20) {ForEach(1...20, id: \.self) { index inColor.blue.frame(height: 100).overlay(Text("\(index)").foregroundStyle(.white).font(.title)).cornerRadius(10)}}.padding()
}
七、进度指示器
7.1、ProgressView - 进度条
// 不确定进度
ProgressView("加载中...")// 确定进度
@State private var progress = 0.5ProgressView(value: progress).progressViewStyle(.linear) // 线性样式// 环形进度
ProgressView(value: progress).progressViewStyle(.circular)
7.2、ActivityIndicator - 活动指示器 (UIKit桥接)
struct ActivityIndicator: UIViewRepresentable {func makeUIView(context: Context) -> UIActivityIndicatorView {let view = UIActivityIndicatorView(style: .large)view.startAnimating()return view}func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {}
}// 使用
ActivityIndicator()
八、容器视图
8.1、VStack/HStack/ZStack - 基础布局
ZStack { // 层叠布局Color.blue.opacity(0.2)VStack(spacing: 20) { // 垂直布局Text("标题").font(.title)HStack { // 水平布局Image(systemName: "star.fill")Text("5星评价")}}
}
.frame(height: 200)
.cornerRadius(15)
8.2、LazyVStack/LazyHStack - 懒加载布局
ScrollView {LazyVStack { // 只渲染可见部分ForEach(1...1000, id: \.self) { item inText("项目 \(item)").padding().onAppear { print("加载项目 \(item)") }}}
}
8.3、Group/GroupBox - 内容分组
Group {Text("第一行")Text("第二行")
}GroupBox(label: Label("设置", systemImage: "gear")) {Toggle("选项1", isOn: .constant(true))Toggle("选项2", isOn: .constant(false))
}
九、导航相关
9.1、NavigationStack - 导航栈
struct ContentView: View {var body: some View {NavigationStack {List {NavigationLink("个人资料", value: "profile")NavigationLink("设置", value: "settings")}.navigationDestination(for: String.self) { id inswitch id {case "profile": ProfileView()case "settings": SettingsView()default: EmptyView()}}.navigationTitle("首页")}}
}
9.2、TabView - 标签页
TabView {HomeView().tabItem {Label("首页", systemImage: "house")}ProfileView().tabItem {Label("我的", systemImage: "person")}
}
.tint(.purple) // 标签颜色
十、弹窗与提示
10.1、Alert - 警告框
@State private var showAlert = falseButton("显示警告") {showAlert = true
}
.alert("确认删除?", isPresented: $showAlert) {Button("删除", role: .destructive) {}Button("取消", role: .cancel) {}
} message: {Text("此操作不可恢复")
}
10.2、Sheet - 底部表单
@State private var showSheet = falseButton("显示表单") {showSheet = true
}
.sheet(isPresented: $showSheet) {VStack {Text("表单内容")Button("关闭") {showSheet = false}}.presentationDetents([.medium, .large]) // 高度控制 (iOS 16+)
}
10.3、Toast - 提示 (自定义实现)
struct ToastModifier: ViewModifier {@Binding var isShowing: Boollet message: Stringfunc body(content: Content) -> some View {ZStack {contentif isShowing {VStack {Spacer()Text(message).padding().background(Color.black.opacity(0.7)).foregroundStyle(.white).cornerRadius(8).transition(.opacity)}.padding().onAppear {DispatchQueue.main.asyncAfter(deadline: .now() + 2) {withAnimation {isShowing = false}}}}}}
}// 使用
Button("显示Toast") {showToast = true
}
.modifier(ToastModifier(isShowing: $showToast, message: "操作成功"))
十一、形状与绘图
11.1、基础形状
VStack(spacing: 20) {Circle().fill(.red).frame(width: 80, height: 80)Rectangle().fill(.blue.gradient).frame(width: 150, height: 80)Capsule().fill(.green).frame(width: 200, height: 60)
}
11.2、自定义形状
struct Triangle: Shape {func path(in rect: CGRect) -> Path {var path = Path()path.move(to: CGPoint(x: rect.midX, y: rect.minY))path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))path.closeSubpath()return path}
}// 使用
Triangle().fill(.orange).frame(width: 100, height: 100)
十二、高级控件
12.1、Canvas - 绘图画布 (iOS 15+)
Canvas { context, size in// 绘制矩形let rect = CGRect(x: 50, y: 50, width: 200, height: 100)context.fill(Path(rect), with: .color(.blue))// 绘制文本let text = "SwiftUI绘图"context.draw(Text(text).font(.title), at: CGPoint(x: size.width/2, y: 200))
}
.frame(height: 300)
12.2、Charts - 图表框架 (iOS 16+)
import Chartsstruct SalesData {let month: Stringlet revenue: Double
}let data = [SalesData(month: "1月", revenue: 5000),SalesData(month: "2月", revenue: 8000),SalesData(month: "3月", revenue: 6500)
]Chart(data) {BarMark(x: .value("月份", $0.month),y: .value("收入", $0.revenue)).foregroundStyle(by: .value("月份", $0.month))
}
.frame(height: 200)
.padding()
最佳实践建议
1、组合使用:通过组合简单控件创建复杂UI
func InfoCard(title: String, value: String) -> some View {VStack(alignment: .leading) {Text(title).font(.caption).foregroundStyle(.secondary)Text(value).font(.title2)}.padding().background(RoundedRectangle(cornerRadius: 10).fill(Color(.systemBackground))).shadow(radius: 2)
}
2、响应式设计:使用 @ViewBuilder
和条件语句
@ViewBuilder
var loadingView: some View {if isLoading {ProgressView()} else {ContentView()}
}
3、平台适配
.padding()
#if os(iOS)
.background(Color(.systemGray6))
#endif
4、性能优化
- 对列表使用
Lazy
视图 - 避免在视图主体中执行繁重操作
- 使用
EquatableView
减少不必要的刷新
SwiftUI 的控件设计遵循声明式理念,通过组合和修饰符可以创建出高度定制化的界面。掌握这些基础控件的使用是构建复杂应用的基础。