此效果是由:http://www.55mx.com/ios/142.html改进而来的,可以参考旧的代码。
当用户点击或者滑动时将会切换视图,开始我使用了固定的参数:
//分段切换视图
struct Segmented:View {
@State private var selector = Segmented.recommended //根据segmented的索引值选择视图
//MARK: Bugs 根据选择手动返回偏移量(居中位置开始)
private var offset:CGFloat{
switch selector {
case .focus: return -98
case .recommended: return -53
case .food: return -9
case .select: return 36
case .dailyCook: return 89
}
}
enum Segmented: String,CaseIterable {
case focus = "关注",recommended = "推荐", food = "食材", select = "精选", dailyCook = "家常菜"
}
var body: some View{
VStack(spacing:2){
HStack(spacing:10){
ForEach(Segmented.allCases ,id: .self){ name in
//点击选择要显示的视图
Button(action: { withAnimation {
selector = name
} }){
Text(name.rawValue)
.modifier(TextFly(isFocus: selector == name))
}
}
}
Divider()
.frame(width: (selector == .dailyCook) ? 55 : 36, height: 2)
.background(Color.pink)
.offset(x: offset)
.animation(.easeInOut(duration: 0.2), value:selector)
//滑动分段切换视图
TabView(selection: $selector) {
FocusView().tabItem{}.tag(Segmented.focus)//关注
RecommendedView().tabItem{}.tag(Segmented.recommended)//推荐(默认显示此项)
FoodView().tabItem{}.tag(Segmented.food)//食材
SelectView().tabItem{}.tag(Segmented.select)//精选
DailyCookView().tabItem{}.tag(Segmented.dailyCook)//家常菜
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))//不显示切换文字
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .never))//不显示背景
}
}
}
虽然在各平台下都可以正常使用,但参数是手动罢黜固定的,不灵活,所以我修改了一下:
//分段切换视图
struct Segmented:View {
@State private var selector = Segmented.recommended //根据segmented的索引值选择视图
@Namespace private var selectors //matchedGeometryEffect需要的参数
enum Segmented: String,CaseIterable {
case focus = "关注",recommended = "推荐", food = "食材", select = "精选", dailyCook = "家常菜"
}
var body: some View{
VStack(spacing:2){
HStack(spacing:10){
ForEach(Segmented.allCases ,id: .self){ name in
ZStack(alignment: .bottom){
if selector == name{
Divider()
.frame(width: (selector == .dailyCook) ? 55 : 36, height: 2)
.background(Color.pink)
.matchedGeometryEffect(id: "top_selectors", in: selectors)
}
Button{ selector = name } //点击选择要显示的视图
label: {
Text(name.rawValue)
.modifier(TextFly(isFocus: selector == name))
.padding(.bottom,3)
}
}.animation(.spring(), value:selector)//iOS15 新写法
}
}
//滑动分段切换视图
TabView(selection: $selector) {
FocusView().tabItem{}.tag(Segmented.focus)//关注
RecommendedView().tabItem{}.tag(Segmented.recommended)//推荐(默认显示此项)
FoodView().tabItem{}.tag(Segmented.food)//食材
SelectView().tabItem{}.tag(Segmented.select)//精选
DailyCookView().tabItem{}.tag(Segmented.dailyCook)//家常菜
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))//不显示切换文字
.indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .never))//不显示背景
}
}
}
我通过ZStack将Divider()与Text显示在同一维度,并在底部对齐,然后使用.matchedGeometryEffect让动画跨视图播放。这样就可以实现下面红线穿越的效果了。
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/165
《SwiftUI带动画效果的分段切换视图》的网友评论(0)