[SwiftUI] Multiple Sheets

Junyoung Park·2022년 8월 18일
0

SwiftUI

목록 보기
7/136
post-thumbnail
post-custom-banner

Multiple Sheets in a SwiftUI View | Continued Learning #7

Multiple Sheets

  • 단일한 뷰에서 여러 개의 시트를 사용하는 방법
  • sheet 메소드 사용 시 동일한 뷰에 전달되는 모델 데이터 값이 다를 경우 클로저에 의해서 원하는 데이터 전달이 되지 않는다.

구현 목표

문제 상황

import SwiftUI

struct SampleModel: Identifiable {
    let id = UUID().uuidString
    let title: String
}

struct MultipleSheetsSample: View {
    @State private var selectedModel = SampleModel(title: "First Start!")
    @State private var showSheet: Bool = false
    var body: some View {
        VStack {
            Button("ONE") {
                selectedModel = SampleModel(title: "ONE")
                showSheet.toggle()
            }
            Button("TWO") {
                selectedModel = SampleModel(title: "TWO")
                showSheet.toggle()
            }
        }
        .sheet(isPresented: $showSheet, content: {
            NextSheetSample(model: selectedModel)
        })
    }
}

struct NextSheetSample: View {
    let model: SampleModel
    var body: some View {
        Text(model.title)
    }
}![](https://velog.velcdn.com/images/j_aion/post/3c8f45f0-edb5-48f6-a81e-60a39dc2525d/image.gif)
  • 시작 뷰에서 서로 다른 버튼을 누를 때 버튼에 의한 데이터가 변경되고, 같은 뷰로 모델 데이터가 전달된다. 즉 모달로 띄워지는 뷰는 버튼에 의해 조작된 데이터를 정확히 받아야 한다.

첫 번째 One 버튼이 눌릴 때 곧바로 One 데이터가 저장된 구조체가 전달되는 게 아니라, 초기값이었던 First Start가 들어 있는 모델이 바인딩되고 있다!
Issue with .sheet() Passing String to a View in SwiftUI 2.0

  • .sheet를 호출하는 핵심 로직인 showSheet@State 변수 변경을 모든 시점에서 읽지 못하기 때문에 생기는 문제점이다. 이를 해결하는 세 가지 방법이 존재한다.

구현 태스크

  1. Binding 사용하기
  • @State를 통해 다음 뷰로 넣어주는 데이터를 @Binding으로 만들자.
  1. .sheets를 여러 개 사용하기
  • sheet를 버튼마다 달자. 하이어러키를 주의.
  1. $item 사용한 .sheet 사용하기
  • .sheet의 이니셜라이저로 $item을 준다. 옵셔널로 선언한 item이 nil이 아니게 될 때 곧바로 모달 뷰가 나온다. isPresented를 위해 별도의 불리언 변수를 선언할 필요가 없는, 확장성이 뛰어난 가장 좋은 솔루션.

핵심 코드

  1. Binding 사용하기
.sheet(isPresented: $showSheet, content: {
            NextSheetSample(model: $selectedModel)
        })
...
@Binding var model: SampleModel
  • 시작 뷰에서는 바인딩되는 @State 변수의 주소를 넘겨주고, 모달 뷰에서는 이를 Binding하면 된다. 하지만 로직이 복잡해질 경우 Binding되는 변수 값이 생각지 않은 대로 작동할 수 있다.
  1. .sheets를 여러 개 사용하기
Button("ONE") {
                showSheet.toggle()
            }
            .sheet(isPresented: $showSheet, content: {
                NextSheetSample(model: SampleModel(title: "ONE"))
  • 더 이상 초깃값은 필요없다. 버튼마다 isPresented 활성화를 위한 별도의 불리언 변수를 토글하고, 그 sheet 메소드마다 해당 버튼에 대한 데이터를 바인딩한다. 하지만 버튼마다 시트를 넣어여하기 때문에 코드가 복잡해지고, 불리언 변수 역시 버튼 수마다 만들어야 한다는 단점이 있다.
  1. $item 사용한 .sheet 사용하기
@State private var selectedModel: SampleModel? = nil
...
.sheet(item: $selectedModel) { model in
            NextSheetSample(model: model)
        }
  • 모달로 넘겨줄 데이터를 옵셔널 데이터로 선언, sheet 메소드의 이니셜라이저로 $item을 선언한다. 즉 널 값이 아니라면 해당 시트에 데이터를 넣어준다는 뜻인데, isPresented 방법과 달리 불리언 변수를 선언할 필요가 없다. 확장성 역시 가장 뛰어나다.

소스 코드

  1. Binding 사용하기
import SwiftUI

struct SampleModel: Identifiable {
    let id = UUID().uuidString
    let title: String
}

struct MultipleSheetsSample: View {
    @State private var selectedModel = SampleModel(title: "First Start!")
    @State private var showSheet: Bool = false
    var body: some View {
        VStack {
            Button("ONE") {
                selectedModel = SampleModel(title: "ONE")
                showSheet.toggle()
            }
            Button("TWO") {
                selectedModel = SampleModel(title: "TWO")
                showSheet.toggle()
            }
        }
        .sheet(isPresented: $showSheet, content: {
            NextSheetSample(model: $selectedModel)
        })
    }
}

struct NextSheetSample: View {
    @Binding var model: SampleModel
    var body: some View {
        Text(model.title)
    }
}
  1. .sheets를 여러 개 사용하기
import SwiftUI

struct SampleModel: Identifiable {
    let id = UUID().uuidString
    let title: String
}

struct MultipleSheetsSample: View {
    @State private var showSheet: Bool = false
    @State private var showSheet2: Bool = false
    var body: some View {
        VStack {
            Button("ONE") {
                showSheet.toggle()
            }
            .sheet(isPresented: $showSheet, content: {
                NextSheetSample(model: SampleModel(title: "ONE"))
            })
            Button("TWO") {
                showSheet2.toggle()
            }
            .sheet(isPresented: $showSheet2, content: {
                NextSheetSample(model: SampleModel(title: "TWO"))
            })
        }
    }
}

struct NextSheetSample: View {
    let model: SampleModel
    var body: some View {
        Text(model.title)
    }
}

struct MultipleSheetsSample_Previews: PreviewProvider {
    static var previews: some View {
        MultipleSheetsSample()
    }
}
  1. $item 사용한 .sheet 사용하기
import SwiftUI

struct SampleModel: Identifiable {
    let id = UUID().uuidString
    let title: String
}

struct MultipleSheetsSample: View {
    @State private var selectedModel: SampleModel? = nil
    var body: some View {
        VStack {
            Button("ONE") {
                selectedModel = SampleModel(title: "ONE")
            }
            Button("TWO") {
                selectedModel = SampleModel(title: "TOW")
            }
        }
        .sheet(item: $selectedModel) { model in
            NextSheetSample(model: model)
        }
    }
}

struct NextSheetSample: View {
    let model: SampleModel
    var body: some View {
        Text(model.title)
    }
}

구현 화면

import SwiftUI

struct SampleModel: Identifiable {
    let id = UUID().uuidString
    let title: String
}

struct MultipleSheetsSample: View {
    @State private var selectedModel: SampleModel? = nil
    var body: some View {
        ScrollView {
            ForEach(0..<50) { index in
                Button("Button # \(index)") {
                    selectedModel = SampleModel(title: "\(index)")
                }
                .frame(maxWidth: .infinity)
            }
        }
        .sheet(item: $selectedModel) { model in
            NextSheetSample(model: model)
        }
    }
}

struct NextSheetSample: View {
    let model: SampleModel
    var body: some View {
        Text(model.title)
    }
}

struct MultipleSheetsSample_Previews: PreviewProvider {
    static var previews: some View {
        MultipleSheetsSample()
    }
}

item 한 번만 사용해서 여러 개의 버튼에 바로 적용하는 확장성.

profile
JUST DO IT
post-custom-banner

0개의 댓글