基础视图组件:从零搭建你的第一个交互界面

说实话,SwiftUI 最让我着迷的地方,就是它把界面搭建变得像搭积木一样简单。你不需要像 UIKit 那样拖拽半天,也不用操心约束冲突。今天我们就来聊聊最常用的六个基础组件——Text、Image、Button、TextField、Toggle 和 Slider。

这些组件,说白了就是你构建任何 App 的「砖块」。我刚开始学 SwiftUI 时,就是靠这几个组件拼出了第一个能用的工具。嗯,咱们一个一个来看。

Text:不只是显示文字

Text 是最简单的组件,但别小看它。我在项目中遇到过不少新手,以为 Text 就是放段文字完事。其实它能做的远不止这些。

Text("Hello, SwiftUI!")
    .font(.title)           // 字体大小
    .fontWeight(.bold)      // 加粗
    .foregroundColor(.blue) // 文字颜色
    .multilineTextAlignment(.center) // 对齐方式
    .lineLimit(2)           // 最多显示两行
    .padding()              // 内边距

你想想看,一个 Text 就能控制字体、颜色、对齐、行数。我个人的习惯是,先把文字内容写好,再慢慢调样式。别一上来就追求完美,先跑起来再说。

小技巧:.lineLimit(nil) 可以让文字自动换行,不限制行数。但要注意,如果文字太长,可能会撑爆布局。

Image:图片加载与处理

Image 组件也很直观。但有个坑——图片资源的管理方式。我刚开始时,直接把图片拖进 Assets 里就完事了。后来发现,用 SF Symbols 更香。

// 加载项目图片
Image("myPhoto")
    .resizable()
    .scaledToFit()
    .frame(width: 200, height: 200)
    .clipShape(Circle())

// 使用 SF Symbols(系统图标)
Image(systemName: "star.fill")
    .foregroundColor(.yellow)
    .font(.largeTitle)

为什么推荐 SF Symbols?因为它是矢量的,不会失真,而且 Apple 官方维护。我曾经在项目里用了 50 多个自定义图标,结果换主题时全要重新切图。后来全换成 SF Symbols,省了至少两天的工作量。

注意:SF Symbols 只在 iOS 13+ 可用。如果你的 App 要支持更早版本,记得用自定义图片。

Button:让用户动起来

Button 是交互的核心。它的基本用法很简单:

Button("点我") {
    print("按钮被点击了")
}

// 带图标的按钮
Button(action: {
    print("收藏成功")
}) {
    Label("收藏", systemImage: "heart.fill")
}

我个人习惯用 Label 来组合图标和文字,这样可读性更好。你想想看,如果按钮只有图标,用户可能不知道它干嘛的。加上文字,一目了然。

还有一个细节——按钮的样式。SwiftUI 默认会给按钮加一个点击高亮效果。如果你想要自定义,可以用 .buttonStyle() 修饰符。

Button("自定义样式") {
    // 点击事件
}
.buttonStyle(.borderedProminent)
.tint(.green)

TextField:让用户输入

TextField 是获取用户输入的主要方式。但有个问题——键盘弹起时,界面会被遮挡。我刚开始做项目时,就因为这个被测试骂了好几次。

@State private var name: String = ""

TextField("请输入你的名字", text: $name)
    .textFieldStyle(.roundedBorder)
    .padding()
    .autocapitalization(.none) // 关闭自动大写
    .disableAutocorrection(true) // 关闭自动纠错

这里要注意 $name 前面的 $ 符号。它表示双向绑定——用户输入的内容会实时更新到 name 变量里。嗯,这是 SwiftUI 的核心机制之一,后面我们会详细讲。

避坑指南:我曾经在表单里用了多个 TextField,结果用户输入时键盘把后面的输入框挡住了。解决方案是用 .keyboardType() 指定键盘类型,或者用 ScrollView 包裹整个表单。

Toggle:开关的优雅实现

Toggle 就是 iOS 里常见的开关控件。用法极其简单:

@State private var isOn: Bool = false

Toggle("开启通知", isOn: $isOn)
    .padding()
    .tint(.blue) // 自定义开关颜色

你可能会问:为什么用 $isOn?因为 Toggle 需要知道当前状态,并且当用户滑动开关时,要更新这个状态。双向绑定在这里体现得淋漓尽致。

我个人的建议是:Toggle 的标签文字要简短。太长的话,开关会被挤到下一行,用户体验不好。

Slider:滑动选择数值

Slider 让用户通过滑动来选择一个数值范围。比如音量调节、亮度调节等。

@State private var value: Double = 0.5

Slider(value: $value, in: 0...1, step: 0.1)
    .padding()
    .accentColor(.orange) // 滑块颜色

这里 in: 0...1 表示范围是 0 到 1,step: 0.1 表示每次滑动增加 0.1。你可以根据需求调整。

我记得有一次做音频播放器,用户要求音量调节要「细腻一点」。我把 step 从 0.1 改成了 0.01,结果用户又说「滑半天调不到位」。后来折中用了 0.05,大家才满意。所以说,步长的选择要结合用户体验,不是越细越好。

小技巧:在 Slider 旁边显示当前数值,让用户知道滑到了什么位置。比如:
Text("\(value, specifier: "%.1f")")

组合使用:一个简单的设置页面

光说理论没意思。咱们把这些组件组合起来,做一个简单的设置页面:

struct SettingsView: View {
    @State private var username: String = ""
    @State private var isNotificationOn: Bool = false
    @State private var volume: Double = 0.5

    var body: some View {
        Form {
            Section(header: Text("个人信息")) {
                TextField("用户名", text: $username)
            }

            Section(header: Text("偏好设置")) {
                Toggle("开启通知", isOn: $isNotificationOn)
                HStack {
                    Text("音量")
                    Slider(value: $volume, in: 0...1)
                    Text("\(volume, specifier: "%.0f%%")")
                }
            }

            Section {
                Button("保存设置") {
                    print("保存成功")
                }
            }
        }
        .padding()
    }
}

你看,用 Form 包裹后,这些组件自动就有了分组和样式。这就是 SwiftUI 的魅力——用最少的代码,做最多的事

总结一下

这六个组件,每个都很简单,但组合起来就能做出很棒的界面。我建议你动手敲一遍代码,别光看。遇到问题很正常,我当初也踩过不少坑。

下一章我们会聊布局容器——VStack、HStack 和 ZStack。到时候你会发现,这些基础组件加上布局容器,能玩出花来。

好了,今天就到这里。有什么问题,欢迎在评论区留言。