SwiftUI - TabView
SwiftUI - TabView
TabView是对UITabBarController的封装。本章包含TabView的基本使用,及TabView如何隐藏TabBar。
一、基本使用
要创建带有选项卡的用户界面,请将View放在TabView中,并对每个选项卡的内容应用tabItem(_:)修饰符。下面创建了一个有2个选项卡的TabView:
struct ContentView: View {
@State private var selection = 1
var body: some View {
TabView(selection: $selection){
FirstTab()
.tabItem {
VStack {
Image("first")
Text("FirstTab")
}
}
.tag(0)
SecondTab()
.tabItem {
VStack {
Image("second")
Text("SecondTab")
}
}
.tag(1)
}
}
}
- TabView只支持Text、Image或Image后跟Text的选项卡项。传递任何其他类型的视图都会导致一个可见但空的选项卡项;
- selection属性指示默认哪个tag选项卡选中;
二、隐藏TabBar
我们知道从TabView导航到下一个页面时需要隐藏TabBar,但是TabView没有的属性直接提供隐藏TabBar的功能。解决思路:TabView底层的实现是UITabBarController,如果我们获取到UITabBarController就能够隐藏TabBar了,这里需要使用到ObservableObject和EnvironmentObject。
- 定义TabBarState
// TabBarState.swift
class TabBarState: ObservableObject {
@Published var hidden : Bool = false
}
- 创建TabBarState对象,并将TabBarState对象通过EnvironmentObject传递给TabView及其子View。监听TabBarState.hidden属性,并设置TabBar.isHidden。
// SceneDelegate.swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let tabBar = TabBarState()
window.rootViewController = UIHostingController(rootView: contentView.environmentObject(tabBar))
self.window = window
window.makeKeyAndVisible()
//监听TabBarState状态
tabBar.$hidden.receive(subscriber: AnySubscriber(receiveSubscription: { (sub) in
sub.request(.unlimited)
}, receiveValue: { (value) -> Subscribers.Demand in
self.tabBarHidden(hidden: value)
return .none
}))
}
}
func tabBarHidden(hidden:Bool){
for viewController in self.window!.rootViewController!.children {
if viewController.isKind(of: UITabBarController.self) {
let tabBarController = viewController as! UITabBarController
if tabBarController.tabBar.isHidden != hidden {
tabBarController.tabBar.isHidden = hidden
}
return
}
}
}
// ContentView.swift
struct ContentView: View {
@State private var selection = 1
@EnvironmentObject var tabBar : TabBarState
var body: some View {
TabView(selection: $selection){
FirstTab()
.environmentObject(tabBar)
.tabItem {
VStack {
Image("first")
Text("FirstTab")
}
}
.tag(1)
SecondTab()
.environmentObject(tabBar)
.tabItem {
VStack {
Image("second")
Text("SecondTab")
}
}
.tag(2)
}
}
}
- TabView子View通过TabBarState设置hidden属性控制TabBar的显示隐藏
// FirstTab.swift
struct FirstTab : View {
@EnvironmentObject var tabBar : TabBarState
var body: some View {
List{
NavigationLink(destination: FirstDetailView().environmentObject(tabBar)){
Text("第1行")
}
NavigationLink(destination: SecondDetailView()
.onAppear{
self.tabBar.hidden = true
}
){
Text("第2行")
}
}
.onAppear{
self.tabBar.hidden = false
}
}
}
// FirstDetailView.swift
struct FirstDetailView : View {
@EnvironmentObject var tabBar : TabBarState
var body: some View {
Text("我是FirstDetailView")
.onAppear{
self.tabBar.hidden = true
}
}
}
FirstDetailView和SecondDetailView两种实现方式都可以。这里用到了View的生命周期onAppear。