背景
本文帮助有Swift基础的同学,快速入门SwiftUI,基于cursour整理
主要分为四个部分:
- 关键字
- Modifier
- 布局
- Viewbuilder
1. 什么是 Modifier?
Modifier 是用于修改视图外观和行为的方法。每个 modifier 都会返回一个新的视图。
swift
Text("Hello")
.font(.title) // 修改字体
.foregroundColor(.blue) // 修改颜色
.padding() // 添加内边距
.background(.yellow) // 添加背景
核心概念:
- ✅ Modifier 不修改原视图,而是创建新视图
- ✅ 支持链式调用
- ✅ 顺序很重要!
2. Modifier 分类
A. 文本 Modifier
swift
Text("SwiftUI Modifier")
// 字体
.font(.title)
.font(.system(size: 24, weight: .bold, design: .rounded))
.fontWeight(.semibold)
// 颜色
.foregroundColor(.blue)
.foregroundStyle(.red)
// 样式
.italic()
.bold()
.underline()
.strikethrough()
.kerning(2) // 字间距
.tracking(3) // 字符间距
.baselineOffset(5) // 基线偏移
// 多行
.lineLimit(3)
.lineSpacing(8)
.multilineTextAlignment(.center)
.truncationMode(.tail)
B. 布局 Modifier
swift
VStack {
Text("布局示例")
}
// 内边距
.padding()
.padding(.horizontal, 20)
.padding(.top, 10)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
// 尺寸
.frame(width: 200, height: 100)
.frame(minWidth: 100, maxWidth: .infinity)
.frame(maxHeight: 300)
// 对齐
.frame(width: 300, height: 200, alignment: .topLeading)
// 偏移
.offset(x: 10, y: 20)
// 位置
.position(x: 100, y: 100)
C. 背景和边框 Modifier
swift
Text("样式示例")
// 背景
.background(.blue)
.background(Color.blue.opacity(0.3))
.background(
LinearGradient(
colors: [.blue, .purple],
startPoint: .leading,
endPoint: .trailing
)
)
// 边框
.border(.red, width: 2)
// 圆角边框
.cornerRadius(10)
.clipShape(RoundedRectangle(cornerRadius: 15))
.clipShape(Circle())
// 描边
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(.red, lineWidth: 2)
)
D. 阴影和效果 Modifier
swift
Text("效果示例")
// 阴影
.shadow(radius: 5)
.shadow(color: .gray, radius: 10, x: 5, y: 5)
// 模糊
.blur(radius: 3)
// 透明度
.opacity(0.8)
// 旋转
.rotationEffect(.degrees(45))
.rotation3DEffect(.degrees(45), axis: (x: 1, y: 0, z: 0))
// 缩放
.scaleEffect(1.5)
.scaleEffect(x: 1.2, y: 0.8)
E. 交互 Modifier
swift
Text("点击我")
// 点击
.onTapGesture {
print("被点击了")
}
.onTapGesture(count: 2) {
print("双击")
}
// 长按
.onLongPressGesture {
print("长按")
}
// 拖拽
.gesture(
DragGesture()
.onChanged { value in
print("拖拽中")
}
)
// 禁用
.disabled(true)
F. 生命周期 Modifier
swift
Text("生命周期")
// 出现
.onAppear {
print("视图出现")
}
// 消失
.onDisappear {
print("视图消失")
}
// 值变化
.onChange(of: someValue) { oldValue, newValue in
print("值改变了")
}
// 任务
.task {
await loadData()
}
3. Modifier 顺序的重要性 ⚠️
这是最容易出错的地方!Modifier 的顺序会产生完全不同的结果。
swift
// 示例 1: 先 padding 后 background
Text("Hello")
.padding(20) // 先添加内边距
.background(.blue) // 背景覆盖整个区域(包括 padding)
// 结果:蓝色背景包含文字和内边距
// 示例 2: 先 background 后 padding
Text("Hello")
.background(.blue) // 背景只覆盖文字
.padding(20) // 在背景外添加内边距
// 结果:蓝色背景只包含文字,外面有空白
// 边框和圆角
Text("示例")
.padding()
.background(.blue)
.cornerRadius(10) // ✅ 正确:圆角应用到背景
.border(.red, width: 2) // 边框在圆角外
Text("示例")
.padding()
.cornerRadius(10) // ❌ 错误:圆角应用到文字(没效果)
.background(.blue)
.border(.red, width: 2)
// Frame 和 Background
Text("示例")
.frame(width: 200, height: 100)
.background(.blue) // ✅ 蓝色填满整个 frame
Text("示例")
.background(.blue)
.frame(width: 200, height: 100) // ❌ 蓝色只在文字周围
4. 自定义 Modifier
方法一:使用 ViewModifier 协议
swift
// 定义自定义 modifier
struct CardModifier: ViewModifier {
func body(content: Content) -> some View {
content
.padding()
.background(.white)
.cornerRadius(10)
.shadow(color: .gray.opacity(0.4), radius: 5, x: 0, y: 2)
}
}
// 扩展 View 以便于使用
extension View {
func cardStyle() -> some View {
self.modifier(CardModifier())
}
}
// 使用
Text("卡片样式")
.cardStyle()
方法二:直接扩展 View
swift
extension View {
func primaryButton() -> some View {
self
.font(.headline)
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(.blue)
.cornerRadius(10)
}
}
// 使用
Text("登录")
.primaryButton()
带参数的自定义 Modifier
swift
struct BorderModifier: ViewModifier {
var color: Color
var width: CGFloat
var cornerRadius: CGFloat
func body(content: Content) -> some View {
content
.padding()
.overlay(
RoundedRectangle(cornerRadius: cornerRadius)
.stroke(color, lineWidth: width)
)
}
}
extension View {
func customBorder(
color: Color = .blue,
width: CGFloat = 2,
cornerRadius: CGFloat = 8
) -> some View {
self.modifier(BorderModifier(
color: color,
width: width,
cornerRadius: cornerRadius
))
}
}
// 使用
Text("自定义边框")
.customBorder(color: .red, width: 3, cornerRadius: 15)
5. 条件 Modifier
swift
// 方法一:使用 @ViewBuilder
extension View {
@ViewBuilder
func `if`<Transform: View>(
_ condition: Bool,
transform: (Self) -> Transform
) -> some View {
if condition {
transform(self)
} else {
self
}
}
}
// 使用
Text("条件样式")
.if(isHighlighted) { view in
view
.font(.largeTitle)
.foregroundColor(.red)
}
// 方法二:三元运算符
Text("示例")
.foregroundColor(isActive ? .blue : .gray)
.font(isLarge ? .title : .body)
// 方法三:使用 modifier
struct ConditionalModifier: ViewModifier {
var condition: Bool
func body(content: Content) -> some View {
if condition {
content
.background(.yellow)
.cornerRadius(10)
} else {
content
.background(.gray)
}
}
}
// 使用
Text("条件")
.modifier(ConditionalModifier(condition: isSpecial))
6. 组合 Modifier 实战示例
swift
struct ProfileCard: View {
@State private var isLiked = false
var body: some View {
VStack(spacing: 12) {
// 头像
Image(systemName: "person.circle.fill")
.resizable()
.scaledToFit()
.frame(width: 80, height: 80)
.foregroundColor(.blue)
.clipShape(Circle())
.overlay(
Circle()
.stroke(.gray, lineWidth: 2)
)
.shadow(radius: 5)
// 名字
Text("张三")
.font(.title2)
.fontWeight(.bold)
// 描述
Text("iOS 开发工程师")
.font(.subheadline)
.foregroundColor(.secondary)
// 按钮
Button(action: { isLiked.toggle() }) {
HStack {
Image(systemName: isLiked ? "heart.fill" : "heart")
Text(isLiked ? "已关注" : "关注")
}
.font(.headline)
.foregroundColor(isLiked ? .red : .white)
.padding(.horizontal, 20)
.padding(.vertical, 10)
.background(isLiked ? .white : .blue)
.cornerRadius(20)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(isLiked ? .red : .blue, lineWidth: 2)
)
}
}
.padding(20)
.background(.white)
.cornerRadius(15)
.shadow(color: .black.opacity(0.1), radius: 10, x: 0, y: 5)
.padding()
}
}
7. 常用 Modifier 组合模板
swift
extension View {
// 卡片样式
func card() -> some View {
self
.padding()
.background(.white)
.cornerRadius(12)
.shadow(color: .gray.opacity(0.3), radius: 8, x: 0, y: 4)
}
// 主按钮样式
func primaryButtonStyle() -> some View {
self
.font(.headline)
.foregroundColor(.white)
.padding()
.frame(maxWidth: .infinity)
.background(
LinearGradient(
colors: [.blue, .purple],
startPoint: .leading,
endPoint: .trailing
)
)
.cornerRadius(10)
.shadow(radius: 5)
}
// 输入框样式
func textFieldStyle() -> some View {
self
.padding()
.background(.gray.opacity(0.1))
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(.gray.opacity(0.5), lineWidth: 1)
)
}
// 标签样式
func tag(color: Color = .blue) -> some View {
self
.font(.caption)
.padding(.horizontal, 12)
.padding(.vertical, 6)
.background(color.opacity(0.2))
.foregroundColor(color)
.cornerRadius(12)
}
}
// 使用示例
struct ContentView: View {
@State private var email = ""
var body: some View {
VStack(spacing: 20) {
// 卡片
VStack {
Text("用户信息")
Text("详细内容")
}
.card()
// 输入框
TextField("邮箱", text: $email)
.textFieldStyle()
// 按钮
Text("登录")
.primaryButtonStyle()
// 标签
HStack {
Text("热门").tag(color: .red)
Text("新品").tag(color: .green)
Text("推荐").tag(color: .blue)
}
}
.padding()
}
}
8. 高级 Modifier 技巧
A. 环境 Modifier
影响所有子视图:
swift
VStack {
Text("标题")
Text("副标题")
Text("内容")
}
.font(.title) // 所有子视图都使用 title 字体
.foregroundColor(.blue) // 所有子视图都是蓝色
B. 几何读取器配合 Modifier
swift
GeometryReader { geometry in
Text("响应式")
.frame(width: geometry.size.width * 0.8)
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
}
C. 动画 Modifier
swift
struct AnimatedView: View {
@State private var isExpanded = false
var body: some View {
RoundedRectangle(cornerRadius: isExpanded ? 50 : 10)
.fill(isExpanded ? .blue : .red)
.frame(width: isExpanded ? 200 : 100, height: 100)
.animation(.spring(response: 0.5, dampingFraction: 0.6), value: isExpanded)
.onTapGesture {
isExpanded.toggle()
}
}
}
9. Modifier 最佳实践
swift
✅ 推荐做法
// 1. 提取重复的 modifier 为自定义 modifier
extension View {
func standardCard() -> some View {
self
.padding()
.background(.white)
.cornerRadius(10)
.shadow(radius: 5)
}
}
// 2. 注意顺序
Text("示例")
.padding()
.background(.blue)
.cornerRadius(10) // 正确顺序
// 3. 使用语义化命名
extension View {
func errorStyle() -> some View {
self.foregroundColor(.red).bold()
}
func successStyle() -> some View {
self.foregroundColor(.green).bold()
}
}
❌ 避免做法
// 1. 避免过长的 modifier 链
Text("Bad")
.font(.title).foregroundColor(.blue).padding().background(.yellow).cornerRadius(10).shadow(radius: 5).opacity(0.9)
// 太长了!应该换行
// 2. 避免重复代码
Text("Button 1")
.padding()
.background(.blue)
.cornerRadius(10)
Text("Button 2")
.padding()
.background(.blue)
.cornerRadius(10)
// 应该提取为自定义 modifier
// 3. 避免错误的顺序
Text("Wrong")
.cornerRadius(10) // 错误:在 background 之前
.background(.blue)
总结
Modifier 核心要点:
- ✅ Modifier 创建新视图,不修改原视图
- ✅ 顺序非常重要
- ✅ 支持链式调用
- ✅ 可以自定义和复用
- ✅ 使用语义化命名
- ✅ 注意性能(避免过度嵌套)