在本章中,你将学会运用MatchedGeometryEffect
构建一个导航菜单。
在构建SwiftUI
应用过程中,咱们常常会运用TabView
构建底部菜单,但更多的时分会因为咱们定制化的需求,需求咱们自己绘制底部菜单。
那么本章中,咱们就来试试构建一个底部导航菜单。
项目建立
首要,创立一个新的SwiftUI
项目,命名为NavigationMenu
。
款式建立
咱们先构建导航菜单的款式部分,咱们先声明一个数组存储咱们需求用到的底部菜单。
let menuItems = ["首页", "发现", "重视", "我的"]
然后,咱们运用ForEach
循环和Text
文字创立导航菜单款式,示例:
HStack {
ForEach(menuItems.indices,id: \.self) { index in
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.background(Capsule().foregroundColor(Color.blue))
.foregroundColor(.white)
}
}
上述代码中,咱们运用ForEach
循环和Text
文字创立了4个导航菜单,并设置了布景填充色为蓝色,文字设置为白色。
菜单切换交互
作用不错,然后给导航菜单加一个状况,当咱们点击菜单时,切换选中。示例:
@State var selectedItem = 0
然后根据选中状况的不同,改换导航菜单的色彩,到达点击切换的作用。示例:
if index == selectedItem {
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.background(Capsule().foregroundColor(Color.blue))
.foregroundColor(.white)
} else {
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.background(Capsule().foregroundColor(Color(.systemGray6)))
.foregroundColor(.black)
.onTapGesture {
selectedItem = index
}
}
上述代码中,咱们经过当时菜单索引index
来判别当时菜单选中状况。
当菜单处于选中时,咱们运用原来蓝色布景 白色字体的款式,当菜单处于未选中时,咱们设置为灰色布景 黑色文字,且点击时切换当时index
为选中索引。
这样,咱们就完结了导航菜单的选中切换交互。
导航切换动画
完结根底的导航菜单切换后,咱们加一点“特效”,咱们运用@Namespace
声明一个动画变量Transition
。示例:
@Namespace private var Transition
然后咱们给导航菜单选中的状况款式加一个过渡动画。示例:
.matchedGeometryEffect(id: "menuItem", in: Transition)
上述代码中,id
和namespace
能够标识哪些视图属于转场动画 Transition
。一起还需求在点击进行状况切换的时分启用动画作用。示例:
.onTapGesture {
withAnimation(.easeOut) {
selectedItem = index
}
}
最终,咱们在调整下位置,看看最终作用。
导航菜单进阶
文字导航现已完结了,在常用的App中会运用图片+文字的形式构建底部导航菜单,咱们这边也试试。
首要先界说好运用的图标数组,示例:
let menuImages = ["house", "paperplane", "heart", "person.2"]
因为文字和图标是纵向摆放,咱们运用VStack
构建页面,示例:
选中部分
VStack {
Image(systemName: menuImages[index]+".fill")
.foregroundColor(Color.blue)
.font(.system(size: 24))
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.foregroundColor(.blue)
}
上述代码中,咱们在VStack
纵向视图中运用Image
图标和Text
文字构架了选中的款式,图标部分运用图标+fill
修饰符变为填充款式,一起图标色彩设置为蓝色。文字部分,咱们把文字色彩修改为蓝色作为选中色彩。
非选中部分
VStack {
Image(systemName: menuImages[index])
.foregroundColor(Color(.systemGray4))
.font(.system(size: 24))
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.foregroundColor(Color(.systemGray4))
}
关于非选中部分,咱们也同样处理,仅仅把色彩变成了灰色。
最终将.matchedGeometryEffect
修饰符和.onTapGesture
调整为VStack
视图外,预览看下作用:
这样,咱们就完结了一个图标加文字的底部导航菜单。
导航菜单布景
当咱们给整个视图填充一个布景色彩时,咱们发现出了点问题。因为咱们底部导航菜单并没有布景色彩,导致在白色布景下看起来还不错,但其他布景色彩下就会和布景色彩融为一体,这不是咱们想要的结果。
咱们测验加一个圆角白色的布景作为底部菜单的显现区域看看。示例:
.padding(.horizontal,30)
.padding(.top,10)
.padding(.bottom,10)
.background(Color.white)
.cornerRadius(60)
.overlay(RoundedRectangle(cornerRadius: 60) .stroke(Color(red: 220/255, green: 223/255, blue: 230/255), lineWidth: 1))
上述代码中,咱们增加了底部菜单左右上下的边距,然后将布景色彩设置为白色,圆角设置为60。
为了能在白色视图布景也能看到底部导航的显现区域,咱们运用overlay
修饰符给底部菜单加了一个边框线。咱们切换回白色视图布景看看作用:
看起来不错的样子!
当然底部导航菜单还有其他款式,能够测验将整个底部菜单区域都变成白色,这是最常用的底部菜单布景的设置办法,也能够在白色的根底上参加含糊通明作用,相似一些社交软件的常用做法,等等。
本章代码
import SwiftUI
struct ContentView: View {
let menuItems = ["首页", "发现", "重视", "我的"]
let menuImages = ["house", "paperplane", "heart", "person.2"]
@State var selectedItem = 0
@Namespace private var Transition
var body: some View {
ZStack {
Color.white
.ignoresSafeArea()
VStack {
Spacer()
HStack {
ForEach(menuItems.indices, id: \.self) { index in
if index == selectedItem {
VStack {
Image(systemName: menuImages[index]+".fill")
.foregroundColor(Color.blue)
.font(.system(size: 24))
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.foregroundColor(.blue)
}.matchedGeometryEffect(id: "menuItem", in: Transition)
} else {
VStack {
Image(systemName: menuImages[index])
.foregroundColor(Color(.systemGray4))
.font(.system(size: 24))
Text(menuItems[index])
.padding(.horizontal)
.padding(.vertical, 4)
.foregroundColor(Color(.systemGray4))
}
.onTapGesture {
withAnimation(.easeOut) {
selectedItem = index
}
}
}
}
}
.padding(.horizontal,30)
.padding(.top,10)
.padding(.bottom,10)
.background(Color.white)
.cornerRadius(60)
.overlay(RoundedRectangle(cornerRadius: 60) .stroke(Color(red: 220/255, green: 223/255, blue: 230/255), lineWidth: 1))
}
}
}
}
祝贺你,完结了本章的一切内容!
快来着手试试吧!
如果本专栏对你有协助,无妨点赞、评论、重视~
我正在参加技术社区创作者签约方案招募活动,点击链接报名投稿。