概述

本文首要共享SwiftUI 完成TabBar的过程,将使用事例的方式进行说明。为什么先共享这个哪?是因为 tabbar 是整个项目结构的基础,项目后续的开发根本依赖tabbar。

剖析

SwiftUI学习分享 -使用SwiftUI实现TabBar

页面布局看,整个页面分成两部分,一个是tab区,一个是内容区,所以咱们在设计tab的时分就需求考虑这两部分,

主体结构

代码如下:

struct ContentView: View {
  var body: some View {
    VStack {
            //这儿为内容区
      HStack {
        Text("home")
      }
      .background(.green)
      Spacer()
            //这儿为tab区
      HStack {
        Text("Text")
      }
      .frame(height: 100)
      .background(.gray)
    }
    .ignoresSafeArea(edges: .bottom)
    .background(.yellow)
  }
}

看下作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

发现是扁的没有充满全屏,咱们能够使用GeometryReader,这个控件官方界说为一个容器视图,将其内容界说为自己的巨细和函数,这个视图返回一个灵活的父布局的首选巨细,读起来有点别扭。 代码如下:

GeometryReader { geometry **in**
    VStack {
        HStack {
            Text("home")
        }
        .background(.green)
        Spacer()
        HStack {
            Text("Text")
        }
        //这儿能够依据自己需求更改高度
        .frame(width: geometry.size.width, height: geometry.size.height/9) 
        .background(.gray)
    }
    .ignoresSafeArea(edges: .bottom)
    .background(.yellow)
}

看下作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

这样看起来大体的结构有了,咱们的主体结构就这样

TabBarIcon

TabBarIcon一般由两部分组成,一个是图片,一个是案牍 代码如下:

struct TabBarIcon: View {
  var body: some View {
    VStack {
      Image(systemName: "chart.pie.fill")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: 40, height: 40)
      Text("主页")
        .font(.footnote)
        .font(.system(size: 16))
    }
  }
}

看下作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

放到主页面中看下:

SwiftUI学习分享 -使用SwiftUI实现TabBar

发现布局不对,并且图片与案牍也是写死的,这样咱们让它活一下,增加 TabBarIcon 的宽高,图片,案牍。

代码如下:

let width, height: CGFloat
let systemIconName, tabName: String
var body: some View {
    VStack {
        Image(systemName: systemIconName)
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: width, height: height)
            .padding(.top, 6)
        Text(tabName)
            .font(.footnote)
            .font(.system(size: 16))
        Spacer()
    }
    .padding(.horizontal, -2)
}

主页面也改一下

struct ContentView: View {
  var body: some View {
    GeometryReader { geometry in
      VStack {
        HStack {
          Text("home")
        }
        .background(.green)
        Spacer()
        ZStack {
          HStack {
            TabBarIcon(width: geometry.size.width/5, height: geometry.size.height/32,systemIconName: "chart.pie.fill", tabName: "主页").frame(maxWidth: .infinity)
            TabBarIcon(width: geometry.size.width/5, height: geometry.size.height/32,systemIconName: "pencil.circle", tabName: "概况").frame(maxWidth: .infinity)
            TabBarIcon(width: geometry.size.width/5, height: geometry.size.height/32,systemIconName: "person.crop.circle.fill", tabName: "我的").frame(maxWidth: .infinity)
          }
          // 将宽度设置为父视图的宽度巨细,高度需求微调,能够设置为详细是数值,比方 100
          .frame(width: geometry.size.width, height: geometry.size.height/9)
          .background(.gray)
        }
        .ignoresSafeArea(edges: .bottom)
        .background(.yellow)
      }
    }
  }
}

看下作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

作用根本达到了,但是现在却还不能点击,也不能切换,也没有点击亮

切换与高亮

完成点击,这时分咱们就需求在 TabBarIcon中增加点击事件,同时点击后图片及案牍都变成高亮显现 为了方便办理及拓展性,咱们创立一个ViewRouter进行办理 代码如下:

enum Page {
  case home
  case detail
  case mine
}
class ViewRouter: ObservableObject {
  @Published var currentPage: Page = .home
}

修正TabBarIcon中代码 代码如下:

struct TabBarIcon: View {
  @StateObject var viewRouter: ViewRouter
  let assignedPage: Page
  let width, height: CGFloat
  let systemIconName, tabName: String
  var body: some View {
    VStack {
      Image(systemName: systemIconName)
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: width, height: height)
        .padding(.top, 6)
      Text(tabName)
        .font(.footnote)
        .font(.system(size: 16))
      Spacer()
    }
    .padding(.horizontal, -2)
    .onTapGesture {
            //点击把当前页付值给viewRouter
      viewRouter.currentPage = assignedPage
    }
        //这俩修正高亮
    .foregroundColor(viewRouter.currentPage == assignedPage ? .green : .white)
  }
}

修正主页代码 代码如下:

struct ContentView: View {
  @StateObject var viewRouter: ViewRouter = ViewRouter()
  var body: some View {
    GeometryReader { geometry in
      VStack {
        HStack {
          Text("home")
        }
        .background(.green)
        Spacer()
        ZStack {
          HStack {
            TabBarIcon(viewRouter: viewRouter, assignedPage: .home, width: geometry.size.width/5, height: geometry.size.height/32,systemIconName: "chart.pie.fill", tabName: "主页").frame(maxWidth: .infinity)
            TabBarIcon(viewRouter: viewRouter, assignedPage: .detail, width: geometry.size.width/5, height: geometry.size.height/32,systemIconName: "pencil.circle", tabName: "概况").frame(maxWidth: .infinity)
                        TabBarIcon(viewRouter: viewRouter, assignedPage: .mine,width: geometry.size.width/5, height: geometry.size.height/32,systemIconName: "person.crop.circle.fill", tabName: "我的").frame(maxWidth: .infinity)
          }
          // 将宽度设置为父视图的宽度巨细,高度需求微调,能够设置为详细是数值,比方 100
          .frame(width: geometry.size.width, height: geometry.size.height/9)
          .background(.gray)
        }
        .ignoresSafeArea(edges: .bottom)
        .background(.yellow)
      }
    }
  }
}

看下作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

这时点击,咱们发现tab已经能够点击了,同时点击也有了高亮显现。那怎样去切换页面呢?

切换页面

首先咱们创立三个页面 Home, Mine, Detail,然后 在内容区进行切换 代码如下:

switch viewRouter.currentPage {
    case .home:
        Home()
    case .detail:
        Detail()
    case .mine:
        Mine()
}

查看作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

页面已经能够正常切换,但是问题又来了,咱们怎样去push一个页面呢?

完成Push

在SwiftUI中有一个控件NavigationView, 这个控件是专门用来完成push作用的,咱们把它包裹住整个内容区域

代码如下:

**struct** ContentView: View {
  @StateObject **var** viewRouter: ViewRouter = ViewRouter()
  **var** body: **some** View {
      GeometryReader { geometry **in**
        NavigationView {
                //内容区代码
        VStack {...}
        .ignoresSafeArea(edges: .bottom)
      }
    }
  }
}

以概况页为例,怎样详细的去push到一个新页面,创立一个新页面PushPage,然后在detai里写push逻辑。

代码如下:

struct Detail: View {
  var body: some View {
    VStack {
      NavigationLink {
        PushPage()
      } label: {
        Text("push")
      }
    }
    .navigationBarTitle("概况页", displayMode: .automatic)
  }
}

查看下作用:

SwiftUI学习分享 -使用SwiftUI实现TabBar

点击push发现能够正常push,同时底部tab也会自动隐藏。

结语

到这儿,咱们的TarBar作用就根本完成了,其中有些UI方面的小细节,需求咱们自己去处理下。