设计思路
- TabView设计:使用
TabView
创建四个标签页,分别为“首页”“发现”“消息”“我的”。为每个标签页设置对应的视图。
- SplitView设计:在“发现”标签页中,使用
SplitView
实现左右分栏。左侧放置分类列表,右侧根据左侧选择的分类展示内容。
- 动画效果:对于右侧内容展示的淡入淡出动画,使用
withAnimation
结合opacity
等修饰符实现。对于TabView
切换的自定义过渡动画,通过tabViewStyle
结合自定义的TabBarStyle
实现。
- 多窗口支持:确保视图布局和交互在不同窗口环境下自适应,通过
GeometryReader
获取窗口大小等信息,进行布局调整。
涉及技术点
- SwiftUI基础组件:
TabView
、SplitView
。
- 动画效果:
withAnimation
、opacity
、tabViewStyle
。
- 响应式布局:
GeometryReader
。
- 数据绑定:
@State
、@Binding
。
代码实现
import SwiftUI
struct Category: Identifiable {
let id = UUID()
let name: String
}
struct ContentView: View {
@State private var selectedTab = 0
@State private var selectedCategory: Category?
let categories = [
Category(name: "Category 1"),
Category(name: "Category 2"),
Category(name: "Category 3")
]
var body: some View {
TabView(selection: $selectedTab) {
HomeView()
.tabItem {
Image(systemName: "house")
Text("首页")
}
.tag(0)
DiscoveryView(selectedCategory: $selectedCategory, categories: categories)
.tabItem {
Image(systemName: "magnifyingglass")
Text("发现")
}
.tag(1)
MessageView()
.tabItem {
Image(systemName: "message")
Text("消息")
}
.tag(2)
ProfileView()
.tabItem {
Image(systemName: "person")
Text("我的")
}
.tag(3)
}
.tabViewStyle(CustomTabBarStyle())
}
}
struct HomeView: View {
var body: some View {
Text("Home View")
}
}
struct DiscoveryView: View {
@Binding var selectedCategory: Category?
let categories: [Category]
var body: some View {
SplitView {
List(categories) { category in
Button(action: {
withAnimation {
selectedCategory = category
}
}) {
Text(category.name)
}
}
} detail: {
if let selectedCategory = selectedCategory {
CategoryContentView(category: selectedCategory)
} else {
Text("Select a category")
}
}
}
}
struct CategoryContentView: View {
let category: Category
var body: some View {
withAnimation(.easeInOut(duration: 0.3)) {
VStack {
Text("Content for \(category.name)")
}
.opacity(1)
}
}
}
struct MessageView: View {
var body: some View {
Text("Message View")
}
}
struct ProfileView: View {
var body: some View {
Text("Profile View")
}
}
struct CustomTabBarStyle: TabBarStyle {
func makeBody(configuration: Configuration) -> some View {
HStack {
ForEach(configuration.tabs, id: \.title) { tab in
VStack {
tab.icon
if configuration.selection?.title == tab.title {
Rectangle()
.fill(Color.blue)
.frame(height: 2)
} else {
Rectangle()
.fill(Color.clear)
.frame(height: 2)
}
}
.onTapGesture {
withAnimation(.easeInOut(duration: 0.3)) {
configuration.selection = tab.value
}
}
}
}
.padding(.horizontal)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}