【问题标题】:SwiftUI: Adding item creates gap in NavigationView ListsSwiftUI:添加项目会在 NavigationView 列表中创建间隙
【发布时间】:2021-07-17 11:10:59
【问题描述】:

我有一个通常格式很好的列表。当我更新数组项并重新添加元素时,它会在列表中引入一个大空间,为某些行增加额外的高度。

这里是列表:

点击添加按钮,新项目被添加了额外的高度:

奇怪的是,如果你用添加按钮玩“田径”并快速多次点击它,一切都会正常。

下面是一些演示问题的代码:

import SwiftUI

var newIndex = 0

var newItems = ["Echo", "Tango", "Hotel", "Alpha", "November", "Kilo", "Yankee", "Oscar", "Uniform", "Indigo", "Romeo", "Whisky", "Lima", "Victor", "Charlie", "Foxtrot", "Delta", "Xray", "Papa", "Juliet", "Bravo", "Golf", "Quebec", "Mike", "Sierra", "Zulu"]

struct ContentView: View
{
    @State var mainList:[String] = ["Echo", "Tango", "Hotel", "Alpha", "November", "Kilo", "Yankee", "Oscar", "Uniform", "Indigo", "Romeo", "Whisky", "Lima", "Victor", "Charlie", "Foxtrot", "Delta", "Xray", "Papa", "Juliet", "Bravo", "Golf", "Quebec", "Mike", "Sierra", "Zulu"].sorted()
    @State var selectedItem:String? = "Echo"
    var body: some View
    {
        NavigationView
        {
            List()
            {
                ForEach(mainList, id: \.self)
                {item in
                    NavigationLink(destination: DetailView(item: item), tag: item, selection: $selectedItem, label:
                    {
                        Text("\(item)")
                    })

                 }
            }
        }
        .toolbar
        {
            Button(action: {addNewItem()})
            {
                Label("Select", systemImage: "square.and.pencil")
            }
          }
    }
    
    func addNewItem()
    {
        if newIndex == newItems.count
        {
            newIndex = 0
        }
        let item = newItems[newIndex]
        if mainList.contains(item)
        {
            mainList = mainList.filter({ $0 != item })
        }
        mainList.append(item)
        selectedItem = item
        newIndex += 1
    }
    
}

struct DetailView: View
{
    @State var item: String

    var body: some View
    {
        Text(item)
    }
}

我发现在这种情况下,它是由 filter 命令引起的,但我在我的应用程序的许多列表中都看到了这种行为。我认为这是由于在同一个列表中删除和添加内容引起的。

【问题讨论】:

    标签: macos swiftui


    【解决方案1】:

    试试这个:

    Text("\(item)").fixedSize()
    

    并将 .toolbar 附加到 List 而不是 NavigationView。

    【讨论】:

    • 这确实以某种方式解决了它,但我的实际代码需要一个多变量高度行而不是单行固定行高。尽管它修复了这个简单的示例,但实际上并没有解决我的根本问题。
    【解决方案2】:

    这是 Xcode Beta 1、2 / macOS 12 Beta 1 中的一个相当大的错误。问题是,您使用 String 本身作为 ID,这意味着如果两个字符串相同,它们将被视为一个项目List:

    ForEach(mainList, id: \.self)
    

    这可能是你想要的。但是,在函数addNewItem() 中,出现了:

    mainList = mainList.filter({ $0 != item })
    // ...
    mainList.append(item)
    

    可以删除和附加相同的项目。因此List 将重新计算高度,并将相同的项目从原来的位置移动到底部,这会导致错误。

    一个不完美的解决方案是您可以将项目包装在提供显式 ID 的结构中,如下所示:

    struct Item: Identifiable {
        let id = UUID()
        
        let value: String
        // Other properties in the future...
    }
    

    并且每次你想添加一个新项目时,都会创建一个副本:

    items = items.filter { $0.value != item }
            
    let newItem = Item(value: item)
    items.append(newItem)
    

    这样,List 就不会将新旧视为同一个项目并产生移动动画。完整代码:

    struct Item: Identifiable {
        let id = UUID()
        
        let value: String
        // Other properties in the future...
    }
    
    var nextItemIndex = 0
    let itemsRow = ["Echo", "Tango", "Hotel", "Alpha", "November", "Kilo", "Yankee", "Oscar", "Uniform", "Indigo", "Romeo", "Whisky", "Lima", "Victor", "Charlie", "Foxtrot", "Delta", "Xray", "Papa", "Juliet", "Bravo", "Golf", "Quebec", "Mike", "Sierra", "Zulu"]
    
    struct ContentView: View {
        @State private var items: [Item] = itemsRow.sorted().map { Item(value: $0) }
        @State private var selected: UUID?
        
        var body: some View {
            NavigationView {
                List {
                    ForEach(items) { item in
                        NavigationLink(destination: DetailView(value: item.value),
                                       tag: item.id, selection: $selected) {
                            Text(item.value)
                        }
                     }
                }
            }
            .toolbar {
                Button(action: addNewItem) {
                    Label("Select", systemImage: "square.and.pencil")
                }
            }
        }
    }
    
    extension ContentView {
        private func addNewItem() {
            let item = itemsRow[nextItemIndex]
            nextItemIndex = (nextItemIndex + 1) % itemsRow.count
            
            items = items.filter { $0.value != item }
            
            let newItem = Item(value: item)
            items.append(newItem)
            
            selected = newItem.id
        }
    }
    

    让我们看看它是否会在下一个 macOS Beta 中修复。

    更新:它已在 macOS 12 Beta 3 上修复。现在您不必复制了。

    【讨论】:

    • 谢谢你解决了我的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 2020-07-10
    相关资源
    最近更新 更多