[SwiftUI Bootcamp] Intermediate2

Woozoo·2023년 1월 22일
0

[SwiftUI]

목록 보기
17/26

ScrollViewReader

스크롤 뷰랑은 살짝 다름
채팅 어플을 예로들면 제일 최근에 대한 내용이 상단으로 올라오게 해주는 거

struct ScrollViewReaderBootcamp: View {
    var body: some View {
        ScrollView {
            ScrollViewReader { proxy in
                
                Button("Click Here to go to #30") {
                    withAnimation(.spring()) {
                        proxy.scrollTo(30, anchor: .top)
                    }
                }
                
                ForEach(0..<50) { index in
                    Text("This is item #\(index)")
                        .font(.headline)
                        .frame(height: 200)
                        .frame(maxWidth: .infinity)
                        .background(.white)
                        .cornerRadius(10)
                        .shadow(radius: 10)
                        .padding()
                        .id(index)
                }
            }
        }
    }
}

scrollViewReader를 넣어주고, proxy를 이용해서
scrollTo지점을 설정할 수 있음

이 때 id를 ForEach에 붙여줘서 어떤 id로 이동할 것인지 설정도 해줘야함

그런데 대부분의 경우 지금처럼 scrollViewReader안에서 버튼이 존재하기보단
외부의 어떤 버튼을 타고 들어올 거임


텍스트필드랑 버튼을 밖에 만들어주고

버튼이 클릭되면 텍스트 필드에 입력된 값을 가져와서 이동하려는 index로 만들어줌
근데 이러면 proxy를 쓸 수가 없잖음

ForEach루프에서 scrollToIndex값이 .onChange 될 때 proxy를 사용해서 변경된 인덱스 값으로 이동하게 해주는겨


GeometryReader

오브젝트의 정확한 위치나 크기를 줄 때 사용
근데 여러개를 한꺼번에 쓰면 가성비가 안 좋음(computing power를 많이사용함)
웬만하면 GeometryReader를 안 쓰는 쪽으로 구현을 하기로! (꼭 필요할 때만 쓰기)


만약에 이렇게 Screen사이즈로 구현을 하게되면 화면을 돌렸을 때 원하는대로 나오지가 않음!
(스크린의 width값은 고정이니까)


그래서 이렇게 구현해줘야함!
스크린이 돌아가도 그 스크린의 크기에 맞춰서 width를 알아차리게


struct GeometryReaderBootcamp: View {
    
    func getPercentage(geo: GeometryProxy) -> Double {
        let maxDistance = UIScreen.main.bounds.width / 2
        let currentX = geo.frame(in: .global).midX
        return Double(1 - (currentX / maxDistance))
    }
    
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack {
                ForEach(0..<20) { index in
                    GeometryReader { geomtry in
                        RoundedRectangle(cornerRadius: 20)
                            .rotation3DEffect(Angle(degrees: getPercentage(geo: geomtry) * 40),
                                              axis: (x: 0.0, y: 1.0, z: 0.0))
                    }
                    .frame(width: 300, height: 250)
                    .padding()
                }
            }
        }
    }
}

이렇게 화면이 스크롤되는 지점에 따라서 오브젝트의 기울기를 변경해서 3D효과도 구현가능!


Present multiple sheets from a single View

sheet 모디파이어는 잘못 구현하면 가끔만 작동하게됨

struct RandomModel: Identifiable {
    let id: UUID = UUID()
    let title: String
}

struct MultipleSheetsBootcamp: View {
    
    @State var selectedModel: RandomModel = RandomModel(title: "STARTIN TITLE")
    @State var showSheet: Bool = false
    var body: some View {
        VStack(spacing: 20) {
            Button("Button 1") {
                selectedModel = RandomModel(title: "ONE")
                showSheet.toggle()
            }
            
            Button("Button 2") {
                selectedModel = RandomModel(title: "TWO")
                showSheet.toggle()
            }
        }
        .sheet(isPresented: $showSheet) {
            NextScreen(selectedModel: selectedModel)
        }
    }
}

struct NextScreen: View {
    
    let selectedModel: RandomModel
    
    var body: some View {
        Text(selectedModel.title)
            .font(.largeTitle)
    }
}


요렇게 로직을 .sheet에 넣는것도 피해야함
한번에 작동을 안해서

그럼 어떻게 해야하느냐

3가지 정도 방법이 있음

1 - use a binding
2 - use multiple .sheets
3 - use $item

첫번째는

Binding으로 모델을 넘겨주는 거임

근데 가끔 Binding이 불필요한 경우가 있을텐데
그럴 땐 다른 방법을 사용하자


이렇게 버튼에 .sheet을 개별적으로 달아주는 거임
이 때 주의할 점은 sheet이 다른 sheet을 삼키지 않게하는 거!
(지금은 상관이 없는 거 같긴한데 주의해서 사용하자)

또 다른 방법은


.sheet(item: )을 활용하는 거!


이렇게 표현할 sheet이 많아지더라도 다 표현이 가능함

profile
우주형

0개의 댓글