SwiftUI matchedGeometry + LazyVStack = 충돌

Oct 18 2020

이 예제를 작성하는 데 몇 시간이 걸렸고, 내가 잘못하고 있는지 또는 matchedGeometry+를 사용할 때 앱이 충돌하는 버그가 있는지 확실하지 않습니다 LazyVStack.

아래 비디오에서 세 번째 사각형을 클릭하면 앱이 다운되었습니다 (앱 시작시 표시되지 않음). 내가 대체 할 경우 충돌이 사라 LazyVStack와 함께 VStack,하지만 분명히 내가 게으른로드 내 물건을 원한다.

Xcode 버전 : 버전 12.0.1 (12A7300)

struct ContentView: View {
    @Namespace var namespace
    @State var selected: Int?


    var body: some View {
        ZStack {
            VStack { 
                Text("Cool rectangles")
                
                if selected == nil {
                    ScrollView(.vertical, showsIndicators: false) {
                        BoxList(namespace: namespace, selected: $selected)
                    }
                }
            }
            
            if let id = selected {
                Rectangle()
                    .foregroundColor(.red)
                    .matchedGeometryEffect(id: id, in: namespace)
                    .onTapGesture {
                        withAnimation{
                            selected = nil
                        }
                    }

            }

        }
    }
}

struct BoxList: View {
    let namespace: Namespace.ID
    @Binding var selected: Int?
    
    var body: some View {
        LazyVStack {
            ForEach(0..<10){ item in
                Rectangle()
                    .matchedGeometryEffect(id: item, in: namespace)
                    .frame(width: 200, height: 200)
                    .onTapGesture {
                        withAnimation {
                            selected = item
                        }
                    }
            }
        }
    }
}

답변

Asperi Oct 18 2020 at 14:06

문제는 ScrollView일치하는 레이아웃 을 파괴하는 것 입니다.

다음은 고정 된 변형입니다. Xcode 12 / iOS 14로 테스트 됨

struct ContentView: View {
    @Namespace var namespace
    @State var selected: Int?


    var body: some View {
        ZStack {
            VStack {
                Text("Cool rectangles")
                
                  ScrollView(.vertical, showsIndicators: false) {
                        BoxList(namespace: namespace, selected: $selected)
                  }.opacity(selected == nil ? 1 : 0)
            } // << or place here opacity modifier here
            
            if let id = selected {
                Rectangle()
                    .foregroundColor(.red)
                    .matchedGeometryEffect(id: id, in: namespace)
                    .onTapGesture {
                        withAnimation{
                            selected = nil
                        }
                    }

            }

        }
    }
}

struct BoxList: View {
    let namespace: Namespace.ID
    @Binding var selected: Int?
    
    var body: some View {
        LazyVStack {
            ForEach(0..<10){ item in
                    if item == selected {
                Color.clear     // placeholder to avoid duplicate match id run-time warning
                    .frame(width: 200, height: 200)
                    } else {
                Rectangle()
                    .matchedGeometryEffect(id: item, in: namespace)
                    .frame(width: 200, height: 200)
                    .onTapGesture {
                        withAnimation {
                            selected = item
                        }
                    }
                        }
            }
        }
    }
}