MatchedGeometryEffect 给出不良的 ZIndex 结果

问题描述 投票:0回答:1

在 SwiftUI 中,我在 ZStack 中创建了 2x2 颜色网格。我想单击一种颜色,并在我的 ZStack 中使用 .matchedGeometryEffect 将其扩展为 DetailView,而不具有任何透明度。使用以下代码很容易做到这一点:

import SwiftUI


struct ContentView: View {
    let colors: [Color] = [.red, .orange, .green, .indigo]
    @Namespace var nameSpace
    @State var showDetailView = false
    @State var selectedColorIndex: Int? = nil
    
    var body: some View {
        ZStack {
            Color.blue
            Grid(horizontalSpacing: 0, verticalSpacing: 0) {
                ForEach(0..<2) { row in
                    GridRow {
                        ForEach(0..<2) { column in
                            let index = (row * 2) + column
                            colors[index]
                                .matchedGeometryEffect(id: index, in: nameSpace)
                                .onTapGesture {
                                    withAnimation {
                                        selectedColorIndex = index
                                        showDetailView = true
                                    }
                                }
                                .zIndex(selectedColorIndex == index ? 1 :  0)
                        }
                    }
                }
            }
            if showDetailView {
                if let index = selectedColorIndex {
                    colors[index]
                        .matchedGeometryEffect(id: index, in: nameSpace)
                        .onTapGesture {
                            withAnimation {
                                showDetailView = false
                            }
                        }
                        .zIndex(1)
                }
            }
        }
        .frame(width: 300, height: 300)
    }
}

但是,这会出现以下错误。

匹配几何组 Pair 中的多个插入视图(第一个:1,第二个:SwiftUI.Namespace.ID(id:86))有

isSource: true
,结果未定义。

我了解此错误背后的原因。当呈现较大的细节视图时,我仍然呈现较小的视图。使用逻辑(if 语句)有条件地删除特定的较小视图,从而消除错误消息非常容易。然而,它破坏了我的 ZIndex,并且我尝试过的任何方法都无法让我找到维护我的属性 ZIndex 布局的解决方案。

我想要实现的目标(无错误): Good example

这是我尝试过的众多事情之一。它消除了错误,但破坏了颜色扩展到其他颜色的效果。

ZStack {
            Color.blue
            Grid(horizontalSpacing: 0, verticalSpacing: 0) {
                ForEach(0..<2) { row in
                    GridRow {
                        ForEach(0..<2) { column in
                            let index = (row * 2) + column
                            if index != selectedColorIndex {
                                colors[index]
                                    .matchedGeometryEffect(id: index, in: nameSpace)
                                    .onTapGesture {
                                        withAnimation {
                                            selectedColorIndex = index
                                            showDetailView = true
                                        }
                                    }
                                    .zIndex(selectedColorIndex == index ? 1 :  0)
                            } else { Color.clear}
                        }
                    }
                }
            }
            if showDetailView {
                if let index = selectedColorIndex {
                    colors[index]
                        .matchedGeometryEffect(id: index, in: nameSpace)
                        .onTapGesture {
                            withAnimation {
                                showDetailView = false
                                selectedColorIndex = nil
                            }
                        }
                        .zIndex(1)
                }
            }
        }
        .frame(width: 300, height: 300)

示例没有更多错误,但不是我想要的视觉效果: Less good example

swiftui z-index matchedgeometryeffect
1个回答
0
投票

我也尝试了很多方法,我发现这很有效。

将您的第一个

.matchedGeometryEffect
更改为:

.matchedGeometryEffect(id: index, in: nameSpace)

至:

.matchedGeometryEffect(id: index, in: nameSpace, isSource: !showDetailView)

这可确保始终只有一个

isSource == true
有效。

然后添加:

.transition(.scale(scale: 0.000001))

到您的详细视图以替换默认的淡入过渡。

这是全部代码:

struct ContentView: View {
    let colors: [Color] = [.red, .orange, .green, .indigo]
    @Namespace var nameSpace
    @State var showDetailView = false
    @State var selectedColorIndex: Int? = nil
    
    var body: some View {
        ZStack {
            Color.blue
            Grid(horizontalSpacing: 0, verticalSpacing: 0) {
                ForEach(0..<2) { row in
                    GridRow {
                        ForEach(0..<2) { column in
                            let index = (row * 2) + column
                            colors[index]
                                .matchedGeometryEffect(id: index, in: nameSpace, isSource: !showDetailView)
                                .onTapGesture {
                                    withAnimation {
                                        selectedColorIndex = index
                                        showDetailView = true
                                    }
                                }
                                .zIndex(selectedColorIndex == index ? 1 :  0)
                        }
                    }
                }
            }
            if showDetailView {
                if let index = selectedColorIndex {
                    colors[index]
                        .matchedGeometryEffect(id: index, in: nameSpace)
                        .transition(.scale(scale: 0.000001))
                        .onTapGesture {
                            withAnimation {
                                showDetailView = false
                            }
                        }
                        .zIndex(1)
                }
            }
        }
        .frame(width: 300, height: 300)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.