마이페이지 구성을 할 때, NavigationLink를 많이 사용해야할 경우가 많다.
위 사진과 달리 마이페이지에는 네이게이션 링크를 많이 사용해야할 경우를 대비하여 ForEach를 사용해서 반복되는 코드를 줄이고 싶어서 방법을 찾아보았다!
struct NavigationItem: Identifiable, Hashable {
let id: Int
let title: String
let imageName: String
let destination: AnyView
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
static func == (lhs: NavigationItem, rhs: NavigationItem) -> Bool {
lhs.id == rhs.id
}
}
ForEach를 사용할 때 각 요소들이 고유한 식별자인 'id'를 가지도록 해야한다. 이를 위해서 Identifiable 프로토콜을 준수하도록 만들었다!
변수들은 이동할 항목들의 String 값을 담을 title, 아이콘 이미지를 담을 수 있는 imageName, 그리고 가장 중요한 "어디로 뷰를 이동할 것인지를 나타내는" desination의 타입을 AnyView로 설정해두었다.
또한, ForEach는 요소들이 Hashable 프로토콜을 준수해야 반복이 가능하기 때문에 추가했고 Hashable을 준수하면서 동시에 Equatable 프로토콜도 준수해야 한다. Hashable은 Equatable을 상속하므로, Equatable을 구현해주기 위해 아래와 같은 함수를 추가해야 한다.
static func == (lhs: NavigationItem, rhs: NavigationItem) -> Bool {
lhs.id == rhs.id
}
아래의 코드는 Hashable 프로토콜을 따르기 위해 구현해야 하는 함수이다.
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
struct MyPageView: View {
let navigationItems: [NavigationItem] = [
NavigationItem(id: 0, title: "구독관리", imageName: "doc.text.magnifyingglass", destination: AnyView(SubscriptionView())),
NavigationItem(id: 1, title: "환경설정", imageName: "gear", destination: AnyView(SettingsView())),
NavigationItem(id: 2, title: "계정관리", imageName: "person.crop.circle", destination: AnyView(AccountView()))
]
var body: some View {
NavigationView {
List {
ForEach(navigationItems, id: \.id) { item in
NavigationLink(destination: item.destination) {
Label(item.title, systemImage: item.imageName)
}
}
}
.navigationTitle("Navigation Stack")
}
}
}
navigationItems는 위에서 만든 NavigationItem 구조체를 담을 배열들이고, 텍스트와 사용할 이미지, 이동할 뷰를 넣어서 생성하면 된다.
ForEach 문에는 만든 배열(navigationItems)을 넣고 NavigationLink의 destination엔 item.destination, Label에는 title과 imageName을 넣어서 사용하면 된다!!