👉🏻 하단 탭 메뉴,드롭다운 메뉴에 대한 설명입니다.
Description of the bottom tab menu and drop-down menu.
👉🏻 스크린 파일이 따로 분리되어있지 않습니다.
The screen files are not separated separately.
👉🏻 나머지 설명은 코드 주석을 참조 하세요
Please refer to the code comments for the rest of the explanation.
1.코드/Code
✔️ ContentView.swift
import SwiftUI
// MARK: - 메인 ContentView
struct ContentView: View {
var body: some View {
MainView()
}
}
// MARK: - Screen Enum
enum Screen: String, CaseIterable {
case home = "홈/Home"
case search = "검색/Search"
case settings = "설정/Settings"
var icon: String {
switch self {
case .home: return "house.fill"
case .search: return "magnifyingglass"
case .settings: return "gearshape.fill"
}
}
var title: String {
self.rawValue
}
}
// MARK: - Main View
struct MainView: View {
@State private var selectedTab: Screen = .home
var body: some View {
NavigationStack {
VStack(spacing: 0) {
// 상단 App Bar / Top app bar
TopBar(title: selectedTab.title)
// 본문 (탭에 따른 화면 전환) / Body (Screen switching according to tab)
ZStack {
switch selectedTab {
case .home:
HomeView()
case .search:
SearchView()
case .settings:
SettingsView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(.systemBackground))
// 하단 네비게이션 바 / Bottom navigation bar
BottomNavigationBar(selectedTab: $selectedTab)
}
.ignoresSafeArea(.keyboard)
}
}
}
// MARK: - Top Bar (상단 앱바)
struct TopBar: View {
var title: String
@State private var showLeftMenu = false
@State private var showRightMenu = false
var body: some View {
HStack {
// 왼쪽 메뉴 버튼 / left menu button
Menu {
Button("메뉴1/Menu1", action: { print("메뉴1 선택") })
Button("메뉴2/Menu2", action: { print("메뉴2 선택") })
} label: {
Image(systemName: "line.horizontal.3")
.font(.title2)
.padding(.leading, 16)
}
Spacer()
Text(title)
.font(.headline)
Spacer()
// 오른쪽 드롭다운 메뉴 / Right drop-down menu
Menu {
Button("설정 변경/Change Settings", action: { print("설정 변경 선택 / Select Change Settings") })
Button("로그아웃/Log out", action: { print("로그아웃 선택 / Select logout") })
} label: {
Image(systemName: "ellipsis")
.rotationEffect(.degrees(90))
.font(.title2)
.padding(.trailing, 16)
}
}
.frame(height: 50)
.background(Color(.systemGray6))
}
}
// MARK: - Bottom Navigation Bar (하단 탭바)
struct BottomNavigationBar: View {
@Binding var selectedTab: Screen
var body: some View {
HStack {
ForEach(Screen.allCases, id: \.self) { screen in
Spacer()
VStack {
Image(systemName: screen.icon)
.font(.system(size: 22))
Text(screen.title)
.font(.caption)
}
.foregroundColor(selectedTab == screen ? .blue : .gray)
.onTapGesture {
withAnimation {
selectedTab = screen
}
}
Spacer()
}
}
.padding(.vertical, 8)
.background(Color(.systemGray6))
}
}
// 스크린 / Screens
struct HomeView: View {
var body: some View {
VStack {
Spacer()
Text("홈 화면입니다. / Home Screen")
Spacer()
}
}
}
struct SearchView: View {
var body: some View {
VStack {
Spacer()
Text("검색 화면입니다. / Search Screen")
Spacer()
}
}
}
struct SettingsView: View {
var body: some View {
VStack {
Spacer()
Text("설정 화면입니다./ Settings Screen")
Spacer()
}
}
}
#Preview {
ContentView()
}
✔️ScreenShot
https://youtu.be/MSctu4bMl3I?si=TUHMjG9wdc1UiNTL