SwiftUI 匹配几何 + LazyVStack = 崩溃

Posted

技术标签:

【中文标题】SwiftUI 匹配几何 + LazyVStack = 崩溃【英文标题】:SwiftUI matchedGeometry + LazyVStack = crash 【发布时间】:2020-10-18 13:42:51 【问题描述】:

我花了好几个小时来构建这个示例,我不确定是我做错了什么,还是在使用 matchedGeometry + LazyVStack 时应用程序崩溃了。

在下面的视频中,当我单击第三个矩形时应用程序崩溃(应用程序启动时不可见)。如果我用VStack 替换LazyVStack,崩溃就会消失,但显然我想延迟加载我的东西。

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
                        
                    
            
        
    

【问题讨论】:

【参考方案1】:

问题是你破坏了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
                        
                    
                        
            
        
    

【讨论】:

感谢您的回复,但为什么破坏视图应该是一个问题?当然,人们经常想根据条件显示/隐藏视图。使用 if/else 来显示视图而不是使用 opacity 似乎更自然? 这不是关于通用的显示/隐藏,if 实际上是添加/删除视图,但问题是关于 matchedGeometryEffect 这需要与相同的 id 视图匹配,但是通过删除 ScrollView 可以破坏匹配的配对视图。这就是原因。

以上是关于SwiftUI 匹配几何 + LazyVStack = 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 1 中使用 LazyVStack

SwiftUI 如何创建选择列表的 LazyVStack

SwiftUI LazyVStack 重叠图像

LazyVStack 和 SwiftUI 的性能不佳问题

SwiftUI 中的匹配几何效果不起作用

SwiftUI - tvOS 上的列表 - 顶部渐变