iOS 응용 (SwiftUI)
[iOS - SwiftUI] 1. List 형태 UI - @State를 활용하여 로딩 상태, 로드 상태, 실패 상태 띄우기
jake-kim
2024. 4. 22. 00:42
1. List 형태 UI - @State를 활용하여 로딩 상태, 로드 상태, 실패 상태 띄우기
2. List 형태 UI - pull to refresh, 페이지네이션 구현 방법 (List, refreshable, pagination, @Sendable)
3. List 형태 UI - 검색된 결과 UI에 보여지게 하는 방법 (searchable)
상태 처리 핵심 개념 - @State
- List형태의 UI를 구현하면 항상 로딩, 성공, 실패에 따라 UI를 다르게 보여주어야 하는데 이 때 SwiftUI의 @State를 활용하면 매우 쉽고 빠르게 구현이 가능
- enum으로 로딩, 성공, 실패에 관한 정의를 하고 이 enum 타입의 프로퍼티를 @State로 선언하면 쉽게 상태 관리가 가능
목표) @State로 3가지 상태화면 만들기
상태 UI 구현
- UI를 구현할 때 가장 먼저 해야하는 것은 데이터 모델 정의
- 간혹, 데이터 없이 UI를 먼저 그리는 경우가 있는데 UI를 구현하다보면 결국 그 UI를 띄워야 하는 데이터가 필요하므로 데이터 모델을 가장 먼저 정의하는 것이 중요
enum ViewState {
case loading
case success
case failed
}
- 이 상태를 표현하는 프로퍼티를 @State 로 선언
- 첫 상태는 loading 상태로 초기화
import SwiftUI
struct ContentView: View {
enum ViewState {
case loading
case success
case failed
}
@State private var state = ViewState.loading
}
- 이 state를 바인딩하는 것을 var body: some View 안에 구현
- 네비게이션 타이틀을 사용하기 위해서 Group으로 우선 묶고, 상태가 변하는 테스트를 하기 위해서 onAppear에서 0.5초 후에 failed로 변경
- (단, 네비게이션 타이틀이 보여지기 위해서는 ContentView를 NavigationView로 감싸야 하는데 이 부분은 3번글에서 계속)
var body: some View {
Group {
}
.navigationTitle("This is navigationTitle")
.onAppear(perform: {
Task {
try await Task.sleep(nanoseconds: 500_000_000)
state = .failed
}
})
}
- 이 state를 기준으로 뷰를 그려주면 되므로 switch 사용
Group {
switch state {
case .loading:
case .success:
case .failed:
}
}
...
- loading 상태일 때는 Loading 뷰와 ProgressView 띄워주기
VStack {
Text("loading...")
ProgressView()
}
- success일때는 단순히 문구 띄워주기
case .success:
Text("Success!")
- fail일때는 retry 버튼과 함께 retry 시 성공상태로 변경
VStack {
Text("Failed!!")
Button("Retry") {
state = .loading
Task {
try await Task.sleep(nanoseconds: 500_000_000)
state = .success
}
}
.buttonStyle(.borderedProminent)
}
- 전체 코드
import SwiftUI
struct ContentView: View {
enum ViewState {
case loading
case success
case failed
}
@State private var state = ViewState.loading
var body: some View {
Group {
switch state {
case .loading:
VStack {
Text("loading...")
ProgressView()
}
case .success:
Text("Success!")
case .failed:
VStack {
Text("Failed!!")
Button("Retry") {
state = .loading
Task {
try await Task.sleep(nanoseconds: 500_000_000)
state = .success
}
}
.buttonStyle(.borderedProminent)
}
}
}
.navigationTitle("This is navigationTitle")
.onAppear(perform: {
Task {
try await Task.sleep(nanoseconds: 500_000_000)
state = .failed
}
})
}
}
#Preview {
ContentView()
}
완성)