티스토리 뷰
첫번째 view는 sticky header를 만들어보자. AppStore에서 많이 볼 수 있고, 배너가 있는 view에서 주로 사용된다.
설계
상단에 배너이미지를 넣고 스크롤 할 수 있도록 아래에 적당한 내용을 추가한다. 배너는 이미지와 텍스트로 구성하며 아래로 스크롤을 하면 이미지가 스케일되면서 윗변이 화면의 상단에 붙어있는듯한 효과를 준다.
구현
var body: some View {
ScrollView(.vertical) {
GeometryReader {g in
// content
}
}
.edgeIgnoringSafeArea(.top)
}
스크롤 기능이 있어야하기 때문에 ScrollView로 시작한다. 노치를 무시하기 위해서 상단 SafeArea를 무시하도록 설정한다. 이 안에 세로로 컨텐츠들을 넣으면 된다. 배너는 스크롤을 할 때마다 스케일을 조절할 수 있어야하는데 이 기능을 위해서 Geometry Reader라는 것을 사용한다. GeometryReader는 자신이 화면에서 어떤 위치에 어떤 크기로 그려지고있는지 등 관련 정보를 가지고있다.
이 때 배너로 사용한 이미지의 정렬 때문에 한참 애를 먹었다. aspectRatio와 frame의 상관관계를 정확히 이해하지 못해서 발생한 문제였다. 이미지의 높이를 설정하면 자동으로 넓이도 화면의 넓이에 맞게 조절될 줄 알았는데, 넓이(width)를 명시하지않으면 이미지가 차지할 수 있는 영역만큼 자동으로 조절되고, 그렇게 넓어진 이미지가 GeometryReader 안에 들어가면서 화면을 벗어나게 되는것이다.
GeometryReader에 이미지를 추가하는 코드를 간단하게 적어봤다.
GeometryReader {g in
let yOffset = g.frame(in: .global).minY > 0 ? -g.frame(in: .global).minY : 0
Image("banner")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: g.size.width, height: g.size.height - yOffset)
.offset(y: yOffset)
}
.frame(height: UIScreen.main.bounds.height / 2) // screen size
지금까지 써왔던 View들과 다른점은 closure에 g in이라는 표현이 추가되었다는 점인데, 이건 생성자가 조금 달라서 그렇다. 지금까지 써왔던 다른 View들은 init에서 () -> Content라는 closure를 매개변수로 받는다. 그래서 따로 추가적인 명시 없이 {}만으로 Content를 구성할 수 있었다. 하지만 GeometryReader는 (GeometryProxy) -> Content라는 closure를 매개변수로 받기 때문에 이 프로시 변수를 명시해주어야 한다.
c++을 주로 해서그런가 이런 문법들이 잘 안읽힌다. 알고나면 코드도 간결하고 괜찮아보이는데, swift가 익숙하지 않은 상태에서 이 코드가 무슨일을 하는지 알아내는데 정말 오랜 시간이 걸렸다.
이미지만 추가하면 밋밋하니까 ZStack으로 타이틀 텍스트를 추가해보았다.
GeometryReader {g in
let yOffset = // skip...
ZStack(alignment: Alignment(horizontal: .leading, vertical: .bottom)) {
Image("banner")
// skip...
Text("Title")
.font(.title)
.fontWeight(.heavy)
.offset(y: yOffset)
.padding([.leading, .bottom])
}
} .frame(height: UISCreen.main.bounds.height / 2)
ZStack은 Z축으로 view들을 쌓아서 화면에 보여주는데 좌축 하단에 정렬하도록 설정했다. 이미지 위에 텍스트를 추가하고 크기와 offset을 설정해준다.
이제 하단에 스크롤을 할 수 있을정도로 컨텐츠들을 추가해주면 된다. 긴 글을 써도 좋고, 이미지를 넣어서 쉽게 양을 늘릴 수도 있다.
var body: some View {
ScrollView(.vertical) {
GeometryReader {g in
// skip...
} .frame(height: UIScreen.main.bounds.height / 2)
Image("dummy01")
Image("dummy02")
Text("content")
} .edgeIgnoringSafeArea(.top)
}
Preview
배너 이미지가 화면 상단에 붙어서 스크롤될 때마다 크기와 스케일이 조절된다.
Navigation Node
이전에 Tutorial project를 만들면서 새롭게 추가하는 view들을 Navigation List에 추가하기로 했다. 상세 view는 다 만들었으니 NavigationList에서 보여질 view를 구성하자. 간단하게 배경에 들어갈 썸네일과 타이틀을 ZStack으로 구성한다. 위 내용은 아무데나 들어가도 상관없지만 StickyHeader.swift에 같이 작성하는게 가장 좋아보여서 StickyHeader 상단에 작성했다.
struct StickyHeaderNode: View {
var body: some View {
ZStack(.leading) {
Image("banner")
.resizable()
.aspectRatio(.fill)
.frame(height: 100)
Text("Sticky Header")
.font(.title)
.padding()
}
}
}
그리고 이렇게 만든 Node를 MainView.swift에서 NavigationLink에 추가하면 된다.
NavigationView() {
List() {
NavigationLink(destination: StickyHeader()) {
StickyHeaderNode()
}
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
이제 MainView를 실행해서 StickyHeader 리스트를 터치하면 위에서 만든 StickyHeaderView로 이동한다.
'Programming > SwiftUI' 카테고리의 다른 글
SwiftUI Beginner | Transition and Animation (0) | 2020.11.14 |
---|---|
SwiftUI Beginner | Drawing Path (0) | 2020.10.29 |
SwiftUI Beginner | 기초문법과 Navigation List (0) | 2020.09.15 |
- Total
- Today
- Yesterday
- mongoDB
- 국내여행
- SOCKET
- machine learing
- scala
- 수학
- SwiftUI
- C
- database
- winsock
- game
- ue4
- DesignPattern
- Spring
- C/C++
- Git
- Cocos2d-x
- Java
- SHADER
- 알고리즘
- OS
- rxswift
- swift
- 데이터베이스
- C++
- 자료구조
- 운영체제
- JSP
- ios
- 드라마
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 | 31 |