首页 > 解决方案 > 当视图嵌入在按钮中时,SwiftUI 匹配几何效果“匹配几何组中的多个插入视图对警告”

问题描述

当用户选择不同的选项卡时,我想实现下划线从一个选项卡移动到另一个选项卡的幻灯片动画 在此处输入图像描述

我正在使用matchedGeometryEffect,如下所示:

       HStack(spacing: 15) {
            ForEach(categories, id: \.self) { category in
                let isSelected = selectedVal == category
                Button {
                    withAnimation {
                        selectedVal = category
                    }
                } label: {
                    VStack(spacing: 4) {
                        Text(category)
                            .frame(width: 100)
                        if isSelected {
                            RoundedRectangle(cornerRadius: 5)
                                .frame(width: 50, height: 2)
                                .matchedGeometryEffect(id: "Category", in: animation, isSource: isSelected)
                        }
                    }
                }
            }
        }

这种方法适用于警告Multiple inserted views in matched geometry group Pair<String, ID>(first: "Category", second: SwiftUI.Namespace.ID(id: 10)) have isSource: true, results are undefined.

当我RoundedRectangleButton警告中提取时消失:

      HStack(spacing: 15) {
            ForEach(categories, id: \.self) { category in
                let isSelected = selectedVal == category
                VStack(spacing: 4) {
                    Button(category) {
                        withAnimation {
                            selectedVal = category
                        }
                    }
                    
                    if isSelected {
                        RoundedRectangle(cornerRadius: 5)
                            .frame(width: 50, height: 2)
                            .matchedGeometryEffect(id: "Category", in: animation, isSource: isSelected)
                    }
                }
            }
        }

我怀疑这与Button在第一个解决方案中没有从视图层次结构中删除有关,因此仍然持有RoundedRectangle对 matchGeometry 的引用,因为你不能让源视图“可见”,但我会虽然isSource被设置到选定的状态就可以解决这个问题。有没有解释为什么我在第一种情况下收到警告?

标签: iosswiftanimationswiftui

解决方案


问题是您可以一次仅在一个视图中设置具有相同命名空间的 matchedgeometryeffect。以便 SwiftUI 可以确定要为哪个对象设置动画。这里是你设置几何效果所有三个具有相同命名空间的视图,所以 swiftUI 无法弄清楚如何为所有视图设置动画和布局。

struct ContentView: View {
    
    enum Tab: String {
        case one
        case two
        case three
    }
    
    @State private var selected: Tab = .one
    @Namespace private var tabNameSpace
    
    var body: some View {
        ZStack {
            HStack(spacing: 32) {
                
                ZStack {
                    if selected == .one {
                        Color.red
                            .frame(width: 100, height: 50)
                            .matchedGeometryEffect(id: "namespace", in: tabNameSpace)
                    }
                    
                    Text(Tab.one.rawValue)
                        .frame(width: 100, height: 50)
                        .onTapGesture {
                            withAnimation(.spring()) {
                                selected = .one
                            }
                        }
                }
                
                ZStack {
                    if selected == .two {
                        Color.red
                            .frame(width: 100, height: 50)
                            .matchedGeometryEffect(id: "namespace", in: tabNameSpace)
                    }
                    
                    Text(Tab.two.rawValue)
                        .frame(width: 100, height: 50)
                        .onTapGesture {
                            withAnimation(.spring()) {
                                selected = .two
                            }
                        }
                }
                
                ZStack {
                    if selected == .three {
                        Color.red
                            .frame(width: 100, height: 50)
                            .matchedGeometryEffect(id: "namespace", in: tabNameSpace)
                    }
                    
                    Text(Tab.three.rawValue)
                        .frame(width: 100, height: 50)
                        .onTapGesture {
                            withAnimation(.spring()) {
                                selected = .three
                            }
                        }
                }
                
            }
        }
    }
    
}

推荐阅读