试图了解 .id(_:) 在 SwiftUI 中的工作原理

Posted

技术标签:

【中文标题】试图了解 .id(_:) 在 SwiftUI 中的工作原理【英文标题】:Trying to understand how .id(_:) works in SwiftUI 【发布时间】:2021-11-19 02:50:06 【问题描述】:

我正在尝试使用.id(_:) 使用 ForEach 进行一些程序化滚动,这样每次使用 ForEach 将新部分添加到表单时都会滚动表单。但是,我遇到了一些不良行为,我想了解导致所述行为的机制。正如您在屏幕截图中看到的那样,第三个文本视图甚至没有出现。当我删除 id 方法时,所有三个 Text 视图都会按您的预期显示。

import SwiftUI

struct ContentView: View 
    @State private var array: [Int] = [1]
    var body: some View 
        ScrollViewReader  p in
            NavigationView 
            Form 
                ForEach(self.array, id: \.self)  num in
                    Section 
                        Text("Hello")
                        Text("My name is slim shady")
                        Text("number \(num)")
                    
                    .id(num)
                    .onChange(of: array.count)  count in
                        p.scrollTo((count + 1), anchor: .top)
                    
                
            
            .toolbar 
                ToolbarItem(placement: .bottomBar) 
                    Button("add") 
                        array.append(array.count + 1)
                    
                
            
            
        
    

任何帮助将不胜感激!干杯。

【问题讨论】:

【参考方案1】:

这里有几个问题。我从来没有尝试像这样将Section 放在ForEach 中,但它们显然玩得不好。我将其删除并改用VStack。我不确定你是否可以制作这样的新部分,但这是另一天的问题。

您遇到的ScrollTo 问题是对您实际使用的id 的误解。当您使用无法以其他方式识别的数组实例化ForEach 时,您使用.self 作为id。但是,这意味着您要跟踪元素本身,而不是每个元素的内容。因此,当您尝试将int 放入您的scrollTo() 时,什么都没有发生,因为int 不是您的数组的元素。您需要做的是提供这样的元素:

struct ContentView: View 
    @State private var array: [Int] = [1]
    var body: some View 
        ScrollViewReader  p in
            NavigationView 
                Form 
                    ForEach(self.array, id: \.self)  num in
                        VStack(alignment: .leading) 
                            Text("Hello")
                            Text("My name is slim shady")
                            Text("number \(num)")
                        
                        // num is an element of your array, not an int
                        .id(num)
                        .onChange(of: array.count)  count in
                            // Supply scrollTo with an array element here
                            p.scrollTo(array.last, anchor: .top)
                        
                    
                
                .toolbar 
                    ToolbarItem(placement: .bottomBar) 
                        Button("add") 
                            array.append(array.count + 1)
                        
                    
                
            
        
    

【讨论】:

感谢 Yrb 的回复。我花了很多时间考虑你的评论......我实际上并不认为你提到的是问题。我再次查看了我的代码,我在传递给scrollTo 的参数中犯了一个小数学错误;它应该只是被计数。在我修复它之后,它开始工作,尽管正如你提到的在 ForEach 内创建部分仍然会导致问题。再次感谢您的回复。【参考方案2】:

以防万一有人碰巧读到这篇文章,经过一堆实验,我已经能够完成这项工作。正如 Yrb 提到的,我在屏幕截图中发布的问题似乎是由在 ForEach 内创建部分引起的。但是,我尝试了不同的初始化程序来创建节,只要您为节标题提供视图,它似乎就可以工作。但是我不知道为什么,如果有人有任何见解,请分享。

struct ContentView: View 
    @State private var array: [Int] = [1]
    var body: some View 
        ScrollViewReader  p in
            NavigationView 
                Form 
                    ForEach(self.array, id: \Int.self)  num in
                        Section 
                            TextVeiwshg(num: num)
                         header: 
                            Text("section #\(num)")
                        
                        .id(num)
                    
                
                .toolbar 
                    ToolbarItem(placement: .bottomBar) 
                        Button("add") 
                            array.append(array.count + 1)
                            print(array)
                        
                    
                
            
            .onChange(of: array.count)  count in
                print(array.count)
                withAnimation 
                    p.scrollTo((count), anchor: .top)
                
                print("scrolling to \(count)")
            
        
    

【讨论】:

以上是关于试图了解 .id(_:) 在 SwiftUI 中的工作原理的主要内容,如果未能解决你的问题,请参考以下文章

基于外部单例类中的属性的 SwiftUI 显示表

SwiftUI - 如何修改数组中的文本字段

从 SwiftUI 中的列表中删除绑定

List中的SwiftUI ScrollView在滚动时消失

在 SwiftUI 中按 ID 删除列表中的项目

SwiftUI 试图从 FetchedResults 获取对象但没有找到方法