일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Test
- AlignmentGuide
- Universal Hashing
- 생각
- hstack
- 좌표공간
- 각도
- stack
- Optional Chaining
- Linked List
- nodejs
- vstack
- SWIFT
- Double Linked List
- enum
- swiftUI
- Optional
- Hashing
- 시계방향
- 레이아웃
- 자료구조
- JavaScript
- optional binding
- layout
- Today
- Total
klioop for iOS
SwiftUI AlignmentGuide 2, Custom AlignmentGuide 본문
이번 포스팅에서는 지난 포스팅(https://klioop.tistory.com/31)에 이어서 AlignmentGuide 에 대해 알아보겠습니다.
alignmentGuide 를 적용했을 때 Stack 안에서 뷰 들이 어떻게 정렬될지 예상이 되어야
이번 포스팅을 이해하실 수 있습니다.
시작은 지난 번 포스팅과 동일한 예제로 가겠습니다.
struct DaysView: View {
var body: some View {
VStack {
Day(label: "월요일")
Day(label: "화요일")
Day(label: "수요일")
Day(label: "목요일")
Day(label: "금요일")
Day(label: "토요일")
Day(label: "일요일")
}
.frame(width: 200)
.padding(.vertical)
.border(Color.gray)
}
}
struct Day: View {
let label: String
var body: some View {
Text(label)
.padding(10)
.background(RoundedRectangle(cornerRadius: 8)
.fill(Color.red.opacity(0.9))
)
.foregroundColor(.white)
}
}
Custom AlignmentGuide 는 말 그대로 alignmentGuide 를 커스텀 해서 사용하는 것을 말합니다.
왜 커스텀을 만들어서 사용할까요
가장 주요한 목적은 Stack 이 다른 뷰들 사이에 정렬을 위해서 사용합니다.
먼저 커스텀을 위해서 어떤 과정이 필요한지 알아보겠습니다.
지난 번 포스팅을 보시면 아시겠지만, alignmentGuide 를 명시적으로 이용하려면
Stack Alignment 와 Guide Alignment 가 같아야 합니다.
VStack(alignment: .leading) {
...
SomeView()
.alignmentGuide(.leading) { ... }
...
}
그러면 .leading 처럼, 커스텀 alignment 나타낼 ID 가 필요할 것 같아요.
VStack alignment 의 경우 HorizontalAlignment 타입이므로
이를 extension 해서 하나 만들면 되겠네요.
코드를 작성하고 다시 볼게요.
extension HorizontalAlignment {
enum MyCustomAlignment: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
d.height
}
}
static let myCustomALignment = HorizontalAlignment(MyCustomAlignment.self)
}
MyCustomAlignment 라는 커스텀 정렬을 enum 으로 하나 만들었습니다.
얘는 AlignmentID 프로토콜을 따라야 합니다.
이 프로토콜은 defaultValue 함수를 하나 선언하기를 요구하는데요.
이름에서 추측 가능하듯이 기본 값을 정해주는 함수 입니다.
어떤 것의 기본 값 일까요
지난 번 포스팅에서도 언급했지만 알고있어야 하는 중요한 사실은
Stack 안 모든 뷰들은 각자 명시적으로든, 암묵적으로든 alignmentGuide 를 갖는다는 것이었습니다.
커스텀 alignmentGuide 를 정의한다면 기본적으로
alignmnetGuide 가 명시적으로 정의되지 않을 때 Stack 안 뷰들이 갖는 암묵적인 alignmentGuide 값을
정해주어야 합니다.
따라서 defaultValue 함수는
이 값의 기본 값을 정해주는 함수입니다.
왜 struct이나 class 가 아니라 enum 으로 정의했냐면,
이 경우 객체(instance) 나 상속이 전혀 필요없기 때문입니다.
그리고 HorizontalAlignment 에 myCustomAlignment 속성을 하나 추가했습니다.
HorizontalAlignment 공식문서를 그대로 따른거에요.
방금 만든 커스텀 alignment 를 적용하면 뷰들이 재밌는 형태로 정렬될 것입니다.
기본 값으로 각 뷰의 높이에 해당하는 지점으로 정렬선이 지나가도록 해놓았기 때문인데요.
Day 뷰에 높이를 인자로 받도록 추가하고 커스텀 정렬을 적용해볼게요.
처음 코드와 달라집니다. VStack 의 frame 도 뻇습니다.
struct DaysView: View {
var body: some View {
VStack(alignment: .myCustomALignment, spacing: 5) {
Rectangle()
.fill(Color.primary)
.frame(width: 1)
.alignmentGuide(.myCustomALignment) { d in d[.leading]}
Day(label: "월요일", height: 30)
Day(label: "화요일", height: 40)
Day(label: "수요일", height: 50)
Day(label: "목요일", height: 60)
Day(label: "금요일", height: 50)
Day(label: "토요일", height: 40)
Day(label: "일요일", height: 30)
Rectangle()
.fill(Color.primary)
.frame(width: 1)
.alignmentGuide(.myCustomALignment) { d in d[.leading]}
}
.padding()
.border(Color.gray)
}
}
struct Day: View {
let label: String
let height: CGFloat
var body: some View {
Text(label)
.frame(height: height)
.padding(.horizontal, 15)
.background(RoundedRectangle(cornerRadius: 8)
.fill(Color.red.opacity(0.9))
)
.foregroundColor(.white)
}
}
extension HorizontalAlignment {
enum MyCustomAlignment: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
d.height
}
}
static let myCustomALignment = HorizontalAlignment(MyCustomAlignment.self)
}
Day 뷰들은 alignmentGuide 가 암묵적으로 적용되고 있는데요.
alignmentGuide 의 값으로 defaultValue 에서 정한 기본 값이 적용되고 있다는 말과 동일합니다.
기본 값은 각 뷰의 높이였습니다.
그 말은 각 뷰의 시작점으로부터 그 높이만큼 떨어진 x 지점으로 수평정렬선이 통과한다는 의미입니다.
커스텀 정렬을 어떻게 만드는 지 살펴보고 사용도 해봤는데요.
자, 그럼 커스텀 정렬이 어떤 상황에서 사용되는지 예시를 통해 살펴볼게요.
https://swiftui-lab.com/alignment-guides 에서 사용된 예시를 그대로 사용하겠습니다.
위 구조를 보면 화살표 이미지와 텍스트는 서로 다른 Stack 에 살고 있습니다.
저는 텍스트를 선택했을 때 선택된 텍스트와 이미지가 수직 가운데 정렬되기를 원합니다.
그런데 VStack 의 정렬은 수평정렬 타입이잖아요?
따라서 VStack 정렬로는 수직 정렬을 이용할 수가 없어요.
더욱이, HStack 에 있는 뷰와 VStack 에 있는 뷰를 정렬시키는 거라 기존의 주어진 정렬만으로는 방법이 없습니다.
여기서 커스텀 정렬이 문제를 해결할 수 있습니다!!
ImageTextAlignment 라는 커스텀 정렬을 만들어서 이미지와 선택된 텍스트가 수직 가운데 정렬 되도록 해보겠습니다.
alignmentGuide 가 명시되지 않는 뷰들은 각 Stack 의 정렬을 암묵적으로 따라 정렬될 것입니다.
바로 코드와 결과를 보겠습니다.
struct CustomAlignmentView: View {
let days = ["월요일", "화요일", "수요일", "목요일", "금요일", "토요일", "일요일"]
@State private var position = 1
var body: some View {
HStack(alignment: .imageTextAlignment ) {
Image(systemName: "arrow.right.circle.fill")
.foregroundColor(.red)
.alignmentGuide(.imageTextAlignment) { d in
d[VerticalAlignment.center]
}
VStack {
ForEach(days.indices, id: \.self) { idx in
Group {
if idx == self.position {
Text(days[idx])
.alignmentGuide(.imageTextAlignment) { d in
d[VerticalAlignment.center]
}
} else {
Text(days[idx])
.onTapGesture {
withAnimation(.easeInOut) {
self.position = idx
}
}
}
} // Group 끝
.padding(.vertical, 2)
}
}
} // HStack 끝
.font(.largeTitle)
}
}
extension VerticalAlignment {
enum ImageTextAlignment: AlignmentID {
static func defaultValue(in d: ViewDimensions) -> CGFloat {
d[.bottom]
}
}
static let imageTextAlignment = VerticalAlignment(ImageTextAlignment.self)
}
다시 말하지만, 이미지와 텍스트는 서로 다른 Stack 에서 존재합니다.
여기까지 AlignmentGuide 를 다뤄봤습니다.
제가 다룬 내용들은 거의 전부 https://swiftui-lab.com/alignment-guides 여기를 참고했습니다.
더 자세한 내용들이 많으니 꼭 참고하시길 바라요.
다음 포스팅에서는 GeometryReader 를 정리하겠습니다!
끝!
'SwiftUI' 카테고리의 다른 글
SwiftUI AlignmentGuide 1 (1) | 2021.05.27 |
---|---|
SwiftUI 레이아웃 시스템 2, Stack (0) | 2021.05.22 |
SwiftUI, 좌표공간 각도방향 (0) | 2021.05.21 |
SwiftUI layout 시스템 1, 레이아웃 원칙 (0) | 2021.05.19 |
SwiftUI, 선언적 뷰의 의미 (0) | 2021.05.17 |