Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 리펙토링
- RxCocoa
- uitableview
- collectionview
- Xcode
- Human interface guide
- swiftUI
- rxswift
- Clean Code
- Protocol
- MVVM
- clean architecture
- uiscrollview
- 리펙터링
- tableView
- swift documentation
- map
- combine
- UITextView
- HIG
- UICollectionView
- 리팩토링
- Observable
- ribs
- 애니메이션
- 클린 코드
- SWIFT
- ios
- Refactoring
- 스위프트
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - SwiftUI] 튜토리얼 - 5. 리스트, 데이터 바인딩 (List, onAppear, offSet, ignoresSafeArea, ScrollView) 본문
iOS 튜토리얼 (SwiftUI)
[iOS - SwiftUI] 튜토리얼 - 5. 리스트, 데이터 바인딩 (List, onAppear, offSet, ignoresSafeArea, ScrollView)
jake-kim 2022. 7. 7. 23:33
* 애플 튜토리얼의 프로젝트 파일을 받아서 실습하고 그 중에서 중요한 부분만 포스팅
4강에서 만든 Row
import SwiftUI
struct LandmarkRow: View {
var landmark: Landmark
var body: some View {
HStack {
landmark.image
.resizable()
.frame(width: 50, height: 50, alignment: .leading)
Text(landmark.name)
Spacer() // <-
}
}
}
struct LandmarkRow_Previews: PreviewProvider {
static var previews: some View {
Group { // <-
LandmarkRow(landmark: landmarks[0])
.previewLayout(.fixed(width: 300, height: 70))
LandmarkRow(landmark: landmarks[1]) // <-
.previewLayout(.fixed(width: 300, height: 70))
}
}
}
List 사용 방법
- List 선언
- List의 첫번째 파라미터에는 배열을 주입
- List의 두번째 파라미터에는 각 배열에 해당되는 id를 keyPath로 주입 (즉, Model을 정의할땐 Identifier 타입을 따르고 있어야, List에 데이터를 주입할때도 용이)
- 클로저를 통해서 각 배열의 원소 접근
import SwiftUI
struct LandmarkList: View {
var body: some View {
// 주입되는 landmarks는 전역으로 선언된 mock 데이터
List(landmarks, id: \.id) { landmark in
}
}
}
struct LandmarkList_Previews: PreviewProvider {
static var previews: some View {
LandmarkList()
}
}
- LandmarkRow 생성자에 landmark 데이터 주입
struct LandmarkList: View {
var body: some View {
List(landmarks, id: \.id) { landmark in
LandmarkRow(landmark: landmark) // <-
}
}
}
- List의 디폴트 값
- List는 자동으로 내부에 contentInset을 주어서 List와 내부 row간의 간격이 존재
- 각 Row밑에 separator가 자동으로 생성
데이터 바인딩
- $를 붙여서 데이터 바인딩
- 예제) MapView에서 region이라는 데이터가 변경될때마다 맵의 중앙 좌표가 변경되도록 처리
- MapView 생성
import SwiftUI
import MapKit
struct MapView: View {
var body: some View {
Text("init")
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView()
}
}
- Map이라는 뷰를 사용하고 생성자의 파라미터 값으로는 `Binding<MKCoordinateRegion>`이 필요
import SwiftUI
import MapKit
struct MapView: View {
var body: some View {
Map(coordinateRegion: <#T##Binding<MKCoordinateRegion>#>) // <-
}
}
- 바인딩하기 위해서 @State를 붙인 프로퍼티 선언
struct MapView: View {
@State private var region = MKCoordinateRegion() // <-
var body: some View {
Map(coordinateRegion: <#T##Binding<MKCoordinateRegion>#>)
}
}
- 바인딩은 `$`를 앞에 붙여서 사용
struct MapView: View {
@State private var region = MKCoordinateRegion()
var body: some View {
Map(coordinateRegion: $region) // <-
}
}
- 또 맵뷰가 appear될때 맵의 위치를 이동시켜주어야 하므로, 초기화 값을 사용하기 위해 coordinate 프로퍼티 선언
struct MapView: View {
var coordinate: CLLocationCoordinate2D // <-
@State private var region = MKCoordinateRegion()
var body: some View {
Map(coordinateRegion: $region)
}
}
- .onAppear를 이용하여 화면이 appear될 때 region이 입력되도록 설정
struct MapView: View {
var coordinate: CLLocationCoordinate2D
@State private var region = MKCoordinateRegion()
var body: some View {
Map(coordinateRegion: $region)
.onAppear { // <-
region = MKCoordinateRegion(
center: coordinate,
span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2)
)
}
}
}
네비게이션에 사용할 DetailView 구현
- DetailView 추가
import SwiftUI
struct LandmarkDetail: View {
var body: some View {
Text("Hello, World!")
}
}
struct LandmarkDetail_Previews: PreviewProvider {
static var previews: some View {
LandmarkDetail()
}
}
- DetailView는 컨텐츠가 많이 들어갈 것이므로, ScrollView를 사용
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
ScrollView {
Text("Hello World")
}
}
}
* ScrollView는 내부 컨텐츠의 크기만큼 영역 차지
- MapView추가하고 ignoreSafeArea를 통해 위쪽 safeArea를 침범하지 않도록 설정
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
ScrollView {
MapView(coordinate: landmark.locationCoordinate)
.ignoresSafeArea(edges: .top) // <-
.frame(height: 300)
}
}
}
- CircleImage를 추가하고 offset을 통해서 맵 위에 이미지가 얹혀지는 형태로 구현
struct LandmarkDetail: View {
var landmark: Landmark
var body: some View {
ScrollView {
MapView(coordinate: landmark.locationCoordinate)
.ignoresSafeArea(edges: .top)
.frame(height: 300)
CircleImage(image: landmark.image)
.offset(y: -130)
}
}
}
- CircleImage는 위로 올라온것처럼 보이지만, 차지하고 있는 영역은 기존 위치를 차지하고 있는 중
- padding을 통해 아래 130만큼 채워주면 해결
CircleImage(image: landmark.image)
.offset(y: -130)
.padding(.bottom, -130) // <-
- 그림 하위에 설명을 표출하기위해, VStack과 HStack을 이용하여 처리
VStack(alignment: .leading) {
Text(landmark.name)
.font(.title)
HStack {
Text(landmark.park)
Spacer()
Text(landmark.state)
}
.font(.subheadline)
.foregroundColor(.secondary)
Divider()
Text("About \(landmark.name)")
.font(.title2)
Text(landmark.description)
}
- 너무 딱 달라붙어 있으므로, VStack에 padding()을 적용
VStack(alignment: .leading) {
...
Text("About \(landmark.name)")
.font(.title2)
Text(landmark.description)
}
.padding() // <-
* 참고
https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation
'iOS 튜토리얼 (SwiftUI)' 카테고리의 다른 글
Comments