在UIKit中设置多个tabbar展示需要使用到UITabBarController
在SwiftUI中 由TabView
组件来进行实现,同时TabView
也可以实现PageViewController的效果,
TabView常规用法1
import SwiftUI
struct ZTMinePageView: View {
var body: some View {
TabView{
Text("设置一").tabItem {
Image(systemName: "arkit").foregroundColor(.red)
Text("设置一")
}
Text("设置二").tabItem {
Image(systemName: "star")
Text("设置二")
}
Text("设置三").tabItem {
Image(systemName: "star").foregroundColor(.red)
Text("设置三")
}
Text("设置四").tabItem {
Image(systemName: "star").foregroundColor(.red)
Text("设置四")
}
}
}
}
tabview此时不会绑定对应的selectedIndex,只能在初始化的时候设置对应的index,不能动态设置要展示的tabbar的index,
TabView常规用法2
除了上面的点击tabview切换视图,SwiftUI
还允许我们使用状态来控制当前视图。为此 我们需要四步
- 1.创建一个记录当前显示视图的
@State
属性 - 2.跳转到其他tab中的视图修改该属性
- 3.该属性以
Binding
的形式传给TabView,便于自动跟踪 - 4.告诉SwiftUI 那种值应该显示那个Tab 具体的如下:
import SwiftUI
struct ZTTestPageView: View {
@State private var selectedTab = 0
var body: some View {
TabView(selection: $selectedTab){
Text("设置一").tabItem {
Image(systemName: "arkit").foregroundColor(.red)
Text("设置一")
}.onTapGesture {
self.selectedTab = 3
}.tag(0)
Text("设置二").tabItem {
Image(systemName: "star")
Text("设置二")
}.tag(1)
Text("设置三").tabItem {
Image(systemName: "star").foregroundColor(.red)
Text("设置三")
}.tag(2)
Text("设置四").tabItem {
Image(systemName: "star").foregroundColor(.red)
Text("设置四")
}.tag(3)
}
}
}
上面代码中当我们点击 设置一界面中的text 这时会修改selectedTab
,而我们在上面把TabView
和selectedTab
绑定到一起了,修改selectedTab
的值 TabView
也会切换对应展示的视图。
- 1.
TabView
只支持Text
Image
或Image
后面跟Text
的选项卡。传递其他任何类型的视图都会导致一个可见但空的选项卡 - 2.
selection
属性指示默认选中那个tag
TabView常规用法3
在上面的用法中没有办法对TabbarItem
中的图片做选中和非选中的切换,上面截图中的变化只是系统对选中和非选中的一个颜色的处理,事实上我们的图片都是同一个。在实际项目中,点击tabbar切换视图 底部的图片也会跟着变化,而且在其他界面中也会动态的修改当前TabView
的index。
- 1.创建一个环境对象,在App启动的时候设置要展示的初始值,
- 2.其他要修改的地方 获取环境变量并修改
- 3.
TabView
和环境变量相互绑定,有一方修改 其他方也会跟着变化
1.定义一个全局的环境变量
import SwiftUI
import Combine
final class TabBarIndexObserver: ObservableObject {
@Published
var tabSelected: TabBarItem = .Home
}
2.定义为全局的环境变量 @EnvironmentObject
import SwiftUI
@main
struct SwiftUITestApp: App {
var body: some Scene {
WindowGroup {
ContentView().environmentObject(TabBarIndexObserver())
}
}
}
3.绑定TabView
和环境变量,其中要自己自定义一个TabBarItem
对象,主要是根据当前TabView
中的index 返回 image 和 title,每个展示的视图都要设置tag 否则绑定视图一直展示的都是0,不会切换到其他视图。图片资源可以自己设置。
import SwiftUI
enum TabBarItem: Int {
case Home
case Living
case Message
case Mine
var titleStr: String {
switch self {
case .Home:
return "首页"
case .Living:
return "直播"
case .Message:
return "消息"
case .Mine:
return "我的"
}
}
var normalImage: Image {
var imageName = ""
switch self {
case .Home:
imageName = ""
case .Living:
imageName = ""
case .Message:
imageName = ""
case .Mine:
imageName = ""
}
return Image(imageName)
}
var selectedImage: Image {
var imageName = ""
switch self {
case .Home:
imageName = ""
case .Living:
imageName = ""
case .Message:
imageName = ""
case .Mine:
imageName = ""
}
return Image(imageName)
}
}
在TabView
中进行对应的设置,给每一个视图设置一个唯一的标识,用这个标识符作为被选中的tab,这些标识符被称为Tag
import SwiftUI
struct ContentView: View {
@EnvironmentObject
private var tabbarIndex: TabBarIndexObserver
private var selectedTab: Binding<Int> {
Binding(
get: { tabbarIndex.tabSelected.rawValue },
set: {
tabbarIndex.tabSelected = TabBarItem(rawValue: $0)!
}
)
}
// 设置对应的normal 和 selected图片 要设置TabView 绑定状态 和 每个View的tag值,在点击的时候把值传递给对应的view
var body: some View {
TabView(selection: selectedTab) {
ZTHomePageView()
.tabItem {tabItem(for: .Home)}
.tag(TabBarItem.Home.rawValue)
ZTLivingPageView()
.tabItem {tabItem(for: .Living)}
.tag(TabBarItem.Living.rawValue)
ZTMessagePageView()
.tabItem {tabItem(for: .Message)}
.tag(TabBarItem.Message.rawValue)
ZTMinePageView()
.tabItem { tabItem(for: .Mine) }
.tag(TabBarItem.Mine.rawValue)
}
.font(.headline)
.accentColor(Color.red) // 设置 tab bar 选中颜色
}
private func tabItem(for tab: TabBarItem) -> some View {
print(selectedTab.wrappedValue)
return VStack {
tab.rawValue == selectedTab.wrappedValue ? tab.selectedImage : tab.normalImage
Text(tab.titleStr)
}
}
}
TabView常规用法4---做轮播图
TabView
实现轮播图时不用设置tabItem 需要指定tabView的显示类型为.tabViewStyle(PageTabViewStyle())
具体代码如下
struct ZTMinePageView: View {
//设置定时器 每2s运行一次 mode为 common 在主线程执行 autoconnect 立即开始定时器
let timer = Timer.publish(every: 2, tolerance: 0.5, on: .main, in: .common).autoconnect()
@State private var bannerIndex = 0
var body: some View {
if #available(iOS 15.0, *) {
TabView(selection: $bannerIndex){
Image("test_1").resizable().scaledToFit().tag(0)
Image("test_2").resizable().scaledToFit().tag(1)
Image("test_3").resizable().scaledToFit().tag(2)
Image("test_4").resizable().scaledToFit().tag(3)
}
.background(Color(red: 0.5, green: 0.9, blue: 0.3, opacity: 0.3))
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.onReceive(timer){ time in
self.bannerIndex += 1
if self.bannerIndex > 3{
self.bannerIndex = 0
}
}
.onAppear{
}.onDisappear{
self.timer.upstream.connect().cancel()
}
} else {
}
}
}
其中设置了一个定时器,具体效果如下,如果想要动画 可以自己加上去
TabView
常规用法---隐藏tabbar
App开发中 从一个页面导航到下一个界面时需要隐藏TabBar
,但是现有的SwiftUI 并没有直接提供隐藏TabBar
的方法。如果根视图是一个tabView 在跳转到下一个界面的时候 tabbar并不会主动隐藏,TabView -> NavigationView -> View 这种方法 不会主动隐藏tabbar,具体实现如下
var body: some View {
TabView(selection: selectedTab) {
//在TabView内部做 NavigationView包装
NavigationView{
ZTHomePageView()
}.tabItem {tabItem(for: .Home)}
.tag(TabBarItem.Home.rawValue)
ZTLivingPageView()
.tabItem {tabItem(for: .Living)}
.tag(TabBarItem.Living.rawValue)
ZTMessagePageView()
.tabItem {tabItem(for: .Message)}
.tag(TabBarItem.Message.rawValue)
ZTMinePageView()
.tabItem { tabItem(for: .Mine) }
.tag(TabBarItem.Mine.rawValue)
}
.font(.headline)
.accentColor(Color.red) // 设置 tab bar 选中颜色
}
ZTHomePageView
中对应的Text上添加了跳转事件,
NavigationLink(destination: TestTabView()){
Text("该来的就会来的")
.underline()
.foregroundColor(.yellow)
}
这时候要隐藏底部的tabbar 就需要修改SwiftUI中的层级结构。使用NavigationView
直接包裹TabView
.
var body: some View {
NavigationView{
TabView(selection: selectedTab) {
ZTHomePageView()
.tabItem {tabItem(for: .Home)}
.tag(TabBarItem.Home.rawValue)
ZTLivingPageView()
.tabItem {tabItem(for: .Living)}
.tag(TabBarItem.Living.rawValue)
ZTMessagePageView()
.tabItem {tabItem(for: .Message)}
.tag(TabBarItem.Message.rawValue)
ZTMinePageView()
.tabItem { tabItem(for: .Mine) }
.tag(TabBarItem.Mine.rawValue)
}
.font(.headline)
.accentColor(Color.red) // 设置 tab bar 选中颜色
}
}
再次看下跳转效果
对此还有上面跳转到下一界面 返回按钮的颜色是红色和蓝色 这是因为设置的.accentColor(Color.green)
的问题造成的。
设置Tabbar的背景色
默认情况下 TabView下发的Tabbar是透明的,当页面中的视图过多时会在Tabbar底部展示,而这个时候对TabBar设置一个背景色就可以解决这个问题。在使用TabView的页面的初始化方法init
方法中对下面属性进行修改
init() {
//修改tabbar底部的背景色
UITabBar.appearance().backgroundColor = .blue
UITabBar.appearance().backgroundImage = UIImage()
}
实际效果如下