@ViewBuilder를 사용해보자
먼저 요런 뷰를 만들었음
지금 만들어준 바디에 있는 뷰를 따로 빼서 만들어주자
요렇게!!
근데 지금 헤더뷰 레귤러에 있는 텍스트들 중
Description같은 경우 옵셔널하게 만들어준다면?
요런 if let 으로 감싸준 폼이 되겠죠
잘 나오고 있죠
요렇게 iconName같은 것도 옵셔널로 설정하고 보여주는 것도 가능할 텐데
이걸 제네릭하게 만들어봅시다
HeaderViewGeneric이라는 뷰를 만들어줌
그리고 요렇게 써줬는데
진짜루 제네릭하게 만들어봅시다
struct HeaderViewGeneric<Content:View>: View {
let title: String
let content: Content
var body: some View {
VStack(alignment: .leading) {
Text(title)
.font(.largeTitle)
.fontWeight(.semibold)
content
RoundedRectangle(cornerRadius: 5)
.frame(height: 2)
}
.frame(maxWidth: .infinity,alignment: .leading)
.padding()
}
}
꺽쇠 안으로 Content라는 타입을 설정하고 View프로토콜만 들어올 수 있게 해준 다음에 해당 타입을 받는 content라는 상수를 만들어줬다!!
그리고 사용해보면 content파라미터 에는 어떤뷰든 받을 수 있게됩니다~
사실 이거 조금 더 보기 좋게 만들 수 있습니다!!
우리 뷰들 쓰다보면 content: 이렇게 된거 엔터치면 사라지고 { } 이것만 남잖음
그렇게 바꿔줄 수 있음
아까 헤더뷰제네릭 으로 돌아와서
init될 때 contetn에 @ViewBuilder를 붙여주고,
받는 타입은 없고 Content 제네릭 타입을 반환해주면 끝!
그럼 init안의 self.content = contetnt()가 되어야 겠죠
보이시나요!!
익숙하게 보던 저 snippet이!!
여태까지 많이 사용하던 HStack도 VStack도 다 이걸로 만들어진 거겠죠
응용해봅시다
struct LocalViewBuilder: View {
enum ViewType {
case one, two, three
}
let type: ViewType
var body: some View {
VStack {
if type == .one {
Text("One!")
} else if type == .two {
VStack {
Text("TWOO")
Image(systemName: "heart.fill")
}
} else if type == .three {
Image(systemName: "heart.fill")
}
}
}
}
요렇게 enum 타입으로 파라미터를 뚫었을 때 if 조건문에 걸리면서 case 에 맞는 뷰를 원하는대로 보여줄 수 있겠죠
해당 케이스에 맞는 뷰들을 다 변수로 빼고
if 문들을 섹션이라는 변수로 뺄라고 하면 에러가 발생함!!
어떤 뷰가 뜰지 일정하지 않아서 나오는 에러다
다른 스택뷰에 갇혀 있지 않는 한 요런 것들이 에러메시지로 나오게 됨
요렇게 말여
하지만 마법의 단어 @ViewBuilder를 붙인다면~
에러가 사라집니다 ㅋㅋㅋ
대박
글구 지금 같은 건 switch로 바꿔줄 수도 있겠죠
뷰 빌더는 어썸!!