커스텀한 탭바를 만드는 방법엔 다양한 방법들이 있습니다!
PreferenceKey를 이용해서 자식의 뷰가 업데이트 될 때, 부모의 뷰가 이 것을 알아차리고 스스로를 업뎃할 수 있게 구성해줄 수도 있고
아니면 오늘 만들어볼 SwiftUI의 기본 TabView 컴포넌트랑 함께 커스텀하게 만든 뷰를 위에 올려서 구성해줄 수도 있어요!
두가지 방법을 다 구현해봤었는데 아래 방법이 제일 깔끔한 것 같더라구요
enum Tab: String, CaseIterable {
case home = "house.fill"
case forum = "message.fill"
case study = "folder.fill"
case profile = "person.circle.fill"
var titleText: String {
switch self {
case .home: return "홈"
case .forum: return "게시판"
case .study: return "스터디"
case .profile: return "프로필"
}
}
}Tab의 Selection이 될 enum 을 선언해줬습니다 그리고 rawValue로 sf symbol 이미지를 가져올 수 있게 해줬어요!
다음은 CustomTabBar를 가지고 있을 컨테이너뷰! 이 뷰가 제일 앞단에 보여질거에요
struct CustomTabBar: View {
@State var currentTab: Tab = .home
var body: some View {
HStack(spacing: 0) {
ForEach(Tab.allCases, id: \.rawValue) { tab in
Button {
withAnimation(.spring()) {
currentTab = tab
}
} label: {
VStack(spacing: 1) {
Image(systemName: tab.rawValue)
.font(.subheadline).bold()
.scaleEffect(currentTab == tab ? 1.1 : 0.9)
.frame(maxWidth: .infinity)
.background {
Capsule()
.fill(currentTab == tab ? .green : .clear)
.frame(width: currentTab == tab ? 60 : 0)
.frame(height: 2.2)
.offset(y: -17)
}
Text(tab.titleText)
.font(.caption)
}
.foregroundColor(currentTab == tab ? .green : .gray)
}
.buttonStyle(TabButtonStyle())
}
}
.frame(height: 30)
.padding(.top, 10)
.padding(.bottom, 8)
.background(.ultraThinMaterial)
}
}struct TabButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.scaleEffect(configuration.isPressed ? 0.8 : 1.0)
}
}(View의 extension으로 만들면 더 깔끔하게 쓸 수 있습니다!!)
extension View {
func customButtonStyle() -> some View {
self.buttonStyle(TabButtonStyle())
}
}struct ContentView: View {
@State private var currentTab: Tab = .home
var body: some View {
TabView(selection: $currentTab) {
Text("홈뷰")
.tag(Tab.home)
Text("게시판뷰")
.tag(Tab.forum)
Text("스터디뷰")
.tag(Tab.study)
Text("프로필뷰")
.tag(Tab.profile)
}
}
}여기다가 아까 만든 뷰를 위에 올려버리는 거에요
struct ContentView: View {
@State private var currentTab: Tab = .home
init() {
UITabBar.appearance().isHidden = true
}
var body: some View {
ZStack(alignment: .bottom) {
TabView(selection: $currentTab) {
Text("홈뷰")
.tag(Tab.home)
Text("게시판뷰")
.tag(Tab.forum)
Text("스터디뷰")
.tag(Tab.study)
Text("프로필뷰")
.tag(Tab.profile)
}
.toolbar(.hidden, for: .tabBar)
CustomTabBar(currentTab: $currentTab)
}
}
}탭이 이미 선택이 된 상태일 때 다시 탭을 하면 ScrollViewReader를 이용해서 Scroll이 되게끔 구성해주는 것도 구현해볼 거고
최신 표현인! NavigationStack을 사용해서 코드에서 Pop To Root 같은 것을 쉽게 구현해보기도 하고,
이런 Navigation과 Tab을 관리해주는 객체를 만들어서 조금 더 효율적으로 이런 UI를 구성해보는 것도 만들어볼 예정입니다