闽公网安备 35020302035485号
struct ContentView: View {
var body: some View {
TabView {
Text("首页内容")
.tabItem {
Label("首页", systemImage: "house")
}
Text("设置页面")
.tabItem {
Label("设置", systemImage: "gear")
}
}
}
}
就这么几行代码,一个基本的双标签界面就出来了!在 iOS 16 之后,你还可以使用更简洁的语法:TabView {
Tab("首页", systemImage: "house") {
HomeView()
}
Tab("设置", systemImage: "gear") {
SettingsView()
}
}

TabView {
HomeView()
.tabItem {
Label("首页", systemImage: "house")
}
CartView()
.tabItem {
Label("购物车", systemImage: "cart") // 堆代码 duidaima.com
}
.badge(3) // 显示数字 3
ProfileView()
.tabItem {
Label("我的", systemImage: "person")
}
.badge("!") // 显示感叹号
}
你可以用数字展示具体的未读消息数量,也可以用文本符号(比如"!")表示需要用户注意的事项。在实际项目中,我通常会把徽章跟实际的数据源绑定起来:.badge(cartItems.isEmpty ? nil : cartItems.count)这样当购物车为空时不显示徽章,有商品时就显示具体数量,简直完美!

struct MainTabView: View {
// 使用 @State 追踪当前选中的标签
@Stateprivatevar selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
HomeView()
.tabItem {
Label("首页", systemImage: "house")
}
.tag(0)
ExploreView()
.tabItem {
Label("发现", systemImage: "safari")
}
.tag(1)
ProfileView()
.tabItem {
Label("我的", systemImage: "person")
}
.tag(2)
}
// 使用 toolbar 添加一个测试按钮
.toolbar {
Button("跳转到发现页") {
withAnimation {
selectedTab = 1// 切换到"发现"标签
}
}
}
}
}
关键在于两点:2.使用 tag() 修饰符给每个标签设置一个唯一标识
3.将状态变量通过 selection 参数绑定到 TabView
3.根据不同的用户角色显示不同的初始标签
struct CustomizableTabView: View {
// 使用 @AppStorage 持久化用户的自定义设置
@AppStorage("tab-view-customization")
privatevar customization: TabViewCustomization
var body: some View {
TabView {
HomeTab()
.tabItem {
Label("首页", systemImage: "house")
}
MessageTab()
.tabItem {
Label("消息", systemImage: "message")
}
.customizationID("com.myapp.tab.messages")
SettingsTab()
.tabItem {
Label("设置", systemImage: "gear")
}
.customizationID("com.myapp.tab.settings")
}
.tabViewStyle(.sidebarAdaptable)
.tabViewCustomization($customization)
}
}
要启用这个功能,需要做这几件事:3.添加 .tabViewCustomization() 修饰符并关联一个存储设置的变量
TabView {
// 基础标签
HomeTab()
.tabItem {
Label("首页", systemImage: "house")
}
// 内容相关标签分组
TabSection("内容中心") {
ArticlesTab()
.tabItem {
Label("文章", systemImage: "doc.text")
}
VideosTab()
.tabItem {
Label("视频", systemImage: "play.rectangle")
}
PodcastsTab()
.tabItem {
Label("播客", systemImage: "headphones")
}
}
// 个人相关标签分组
TabSection("个人中心") {
ProfileTab()
.tabItem {
Label("资料", systemImage: "person")
}
SettingsTab()
.tabItem {
Label("设置", systemImage: "gear")
}
}
}
.tabViewStyle(.sidebarAdaptable)
这种分组方式在 iPad 上特别有用——它会在侧边栏中形成层级结构,让导航更加清晰。而在 iPhone 上,它们仍然会以普通标签的形式显示在标签栏中。TabSection("消息中心") {
InboxTab()
.tabItem {
Label("收件箱", systemImage: "tray.and.arrow.down")
}
SentTab()
.tabItem {
Label("已发送", systemImage: "tray.and.arrow.up")
}
}
.sectionActions {
Button("新建消息") {
// 创建新消息的操作
}
Button("标记全部已读") {
// 标记全部已读的操作
}
}
这些操作按钮会显示在分组的标题旁边,为用户提供与该分组相关的快捷功能。struct SocialAppTabView: View {
@StateObjectprivatevar notificationCenter = NotificationCenter()
@Stateprivatevar selection = 0
@AppStorage("tab-customization") privatevar customization: TabViewCustomization
var body: some View {
TabView(selection: $selection) {
// 首页标签
NavigationView {
HomeView(onMessageTap: { goToMessages() })
.navigationTitle("首页")
}
.tabItem {
Label("首页", systemImage: "house")
}
.tag(0)
// 发现内容分组
TabSection("发现") {
NavigationView {
TrendingView()
.navigationTitle("热门")
}
.tabItem {
Label("热门", systemImage: "flame")
}
.tag(1)
NavigationView {
ExploreView()
.navigationTitle("探索")
}
.tabItem {
Label("探索", systemImage: "safari")
}
.tag(2)
}
.customizationID("com.myapp.section.discover")
// 消息标签
NavigationView {
MessageListView()
.navigationTitle("消息")
}
.tabItem {
Label("消息", systemImage: "message")
}
.badge(notificationCenter.unreadMessageCount > 0 ?
notificationCenter.unreadMessageCount : nil)
.tag(3)
.customizationID("com.myapp.tab.messages")
// 个人标签
NavigationView {
ProfileView()
.navigationTitle("我的")
}
.tabItem {
Label("我的", systemImage: "person")
}
.tag(4)
.customizationID("com.myapp.tab.profile")
}
.tabViewStyle(.sidebarAdaptable)
.tabViewCustomization($customization)
.onReceive(notificationCenter.$newMessageReceived) { received in
if received {
// 收到新消息时提示用户
if selection != 3 { // 如果当前不在消息标签
// 这里可以显示一个临时通知
}
}
}
}
privatefunc goToMessages() {
withAnimation {
selection = 3// 跳转到消息标签
}
}
}
// 模拟的通知中心
class NotificationCenter: ObservableObject {
@Publishedvar unreadMessageCount: Int = 0
@Publishedvar newMessageReceived: Bool = false
init() {
// 模拟接收新消息
Timer.scheduledTimer(withTimeInterval: 30, repeats: true) { [weakself] _in
guardletself = selfelse { return }
self.unreadMessageCount += 1
self.newMessageReceived = true
// 堆代码 duidaima.com
// 3秒后重置新消息标志
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.newMessageReceived = false
}
}
}
}
这个例子实现了多种高级功能:.程序化导航(从首页跳转到消息页)
.响应实时通知的逻辑
struct OptimizedTabView: View {
@Stateprivatevar selectedTab = 0
var body: some View {
TabView(selection: $selectedTab) {
LazyView(HomeView())
.tabItem { Label("首页", systemImage: "house") }
.tag(0)
// 其他标签使用 LazyView 包装
}
}
}
// 懒加载包装器
struct LazyView<Content: View>: View {
let build: () -> Content
init(_ build: @autoclosure @escaping () -> Content) {
self.build = build
}
var body: Content {
build()
}
}
这个技巧在有大量标签或标签内容复杂的应用中特别有用。TabView {
// 标签内容
}
.ignoresSafeArea(.keyboard) // iOS 14+
另一种方法是在键盘出现时隐藏标签栏:struct KeyboardAwareTabView: View {
@Stateprivatevar keyboardVisible = false
var body: some View {
TabView {
// 标签内容
}
.opacity(keyboardVisible ? 0 : 1)
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { _in
withAnimation {
keyboardVisible = true
}
}
.onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _in
withAnimation {
keyboardVisible = false
}
}
}
}
3. 处理深色模式下的标签图标TabView {
HomeView()
.tabItem {
Image(systemName: "house")
.environment(\.symbolVariants, .none) // 使用填充样式
Text("首页")
}
}
.accentColor(.orange) // 自定义选中颜色
4. 在 iPad 上适配侧边栏TabView {
// 标签内容
}
.tabViewStyle(DeviceType.isPad ? .sidebar : .automatic)
// 设备类型检测
enum DeviceType {
static var isPad: Bool {
UIDevice.current.userInterfaceIdiom == .pad
}
}
总结