一开始我想到的是方案是使用switch选择视图进行显示,并且利用手势和动画也可以达到想要的效果,后来发现还可以利用TabView来实现自带的滑动切换视图效果。当然我在网上还看到了利用偏移把其它视图挤出屏幕外的方案。在本文里会慢慢收集更多更好的方案供参考。
2021.10.12 : 最后又写了一个改进版本带动画效果的视图切换,可以参考:http://www.55mx.com/ios/165.html
struct Index:View {
private let segmented = ["关注","推荐","食材","精选","家常菜"]
@State private var selector = 1 //根据segmented的索引值选择视图
var body: some View{
VStack{
//分段切换视图
HStack{
ForEach(segmented, id: .self) { name in
Button(action: {
if let index = segmented.firstIndex(of: name){
withAnimation {
selector = index //选择视图
}
}
}, label: {
//顶部切换文本显示样式
if selector == segmented.firstIndex(of: name){
Text(name)
.font(.system(size: 18, weight: .bold))
.overlay(Rectangle().frame(height: 2).offset(y: 4) ,alignment: .bottom)
.foregroundColor(.red)
}else{
Text(name)
.foregroundColor(.black)
}
})
}
}
.padding()
//根据selector分段切换视图
ScrollView{
switch selector{
case 1:
RecommendedView()//推荐(默认显示此项)
case 2:
FoodView()//食材
case 3:
SelectView()//精选
case 4:
DailyCookView()//家常菜
default:
FocusView()//不匹配的情况下显示
}
}
.offset(x:gesturePanOffset.width)
.gesture(panGesture())//拖动手势(切换View)
// .transition(.slide)
// .animation(.easeInOut)
.navigationBarHidden(true) //隐藏包括标题和返回键在内的所有系统导航栏
.navigationBarBackButtonHidden(true)//只隐藏系统导航栏中的返回键
}
}
//平移手势
@GestureState private var gesturePanOffset:CGSize = .zero //手势结束会恢复初值
//手势定义
private func panGesture() -> some Gesture{
DragGesture()
//有空仔细学一下updating到底在做什么
.updating($gesturePanOffset){ lastestGestureValue, gesturePan, animation in
gesturePan = lastestGestureValue.translation //gesturePan的更新会影响$gesturePanOffset的值变化
animation.animation = .easeInOut//拖动的动画处理
}
//手势结束后的操作(循环切换分段View)
.onEnded{ value in
let moveOffset = UIScreen.main.bounds.width / 2 //超过屏幕宽度(计算后的值)才发生偏移
let lastIndex = segmented.endIndex - 1//数组最后一个索引值
//向右拖动
if value.translation.width > moveOffset{
if selector <= 0{
selector = lastIndex
}else{
selector -= 1
}
}
//向左拖动
if -value.translation.width > moveOffset{
if selector >= lastIndex {
selector = 0
}else{
selector += 1
}
}
}
}
}
@State private var selector = Segmented.recommended //根据segmented的索引值选择视图
enum Segmented: String,CaseIterable {
case focus = "关注",recommended = "推荐", food = "食材", select = "精选", dailyCook = "家常菜"
}
var body: some View{
VStack{
//分段切换视图
HStack{
ForEach(Segmented.allCases ,id: .self){ name in
Button(action: {
withAnimation {
selector = name
}
}, label: {
if selector == name{
Text(name.rawValue)
.font(.system(size: 18, weight: .bold))
.overlay(Rectangle().frame(height: 2).offset(y: 4) ,alignment: .bottom)
.foregroundColor(.red)
}else{
Text(name.rawValue)
.foregroundColor(.black)
}
})
}
}
.padding(.top)
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))//不显示背景
}
}
这里由于去掉了自己定义的手势代码,切换选择使用了枚举,所以代码看上去更精简一些。可以根据自己喜欢选择。
TabView还可以切换很多视图,关于介绍可以参考:http://www.55mx.com/ios/127.html
除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/142
《【SwiftUI实战】segmented分段切换视图的几种方案》的网友评论(0)