简体   繁体   English

如何仅显示 SwiftUI 列表中的选定项目?

[英]How can I show only selected items in SwiftUI List?

How can I make a List show a set of selected items when editMode is .inactive and all selectable options when editMode is .active so the user can change the set of selected items?当 editMode 为 .inactive 时,如何让 List 显示一组选定的项目,以及当 editMode 为 .active 时的所有可选选项,以便用户可以更改选定的项目集? Here is what I have tried:这是我尝试过的:

import SwiftUI

struct SelectionView: View {
    @Environment(\.editMode) var editMode
    @State var selectedItems = Set<String>(["1-item", "2-item", "3-item", "4-item"])
    let allItems = ["1-item", "2-item", "3-item", "4-item"]
    var items: [String] {
        if editMode?.wrappedValue == .inactive {
            return Array(selectedItems)
        }
        else {
            return allItems
        }
    }

    var body: some View {
        NavigationView {
            List(items, id: \.self, selection: $selectedItems) { item in
                Text(item)
            }
            .navigationBarItems(trailing: EditButton())
            .navigationBarTitle("Items")
        }
    }
}

The selected array is now unordered as it is generated from a set and I eventually want to have it in the correct order.选定的数组现在是无序的,因为它是从一组生成的,我最终希望它按正确的顺序排列。 But I'm first trying to get the list to work as it is.但我首先试图让列表按原样工作。

Here is approach how it works for me.这是它如何为我工作的方法。 Unfortunately it is not completely nice due to specifics of List internals (or bug)...不幸的是,由于List内部(或错误)的细节,它并不完全好......

The idea is to switch containers of List filtering one of them based on selected items, and the switching itself depends on manual tracking of EditMode思路是切换List容器,根据选中的项目过滤其中一个,切换本身依赖EditMode手动跟踪

Anyway it works (tested with Xcode 11.2/iOS 13.2, as well in Preview)无论如何它都有效(使用 Xcode 11.2/iOS 13.2 以及预览版测试)

struct SelectionView: View {
    @State var editMode: EditMode = .inactive // ! Needed manual to track states

    @State var selectedItems = Set<String>(["1-item", "2-item", "3-item", "4-item"])
    let allItems = ["1-item", "2-item", "3-item", "4-item"]
    var items: [String] {
        allItems.filter { self.selectedItems.contains($0) }
    }

    @State var applyFilter = false
    var body: some View {
        NavigationView {
            VStack {
                List(applyFilter ? items : allItems, id: \.self,
                     selection: $selectedItems) { item in
                        Text(item)
                }
                .navigationBarItems(trailing: EditButton())
                .navigationBarTitle("Items")
            }
//            .environment(\.editMode, $editMode) // << this is how it should be, but crash
            .environment(\.editMode, Binding<EditMode>(get: { self.editMode },
               set: {
                    self.editMode = $0

                    // !!! below is needed workaround, because applying filter directly
                    // on close EditMode result in crash due to cached List internals
                    // until switch EditMode animation is finished completely
                    if $0 == .inactive {
                        DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                            self.applyFilter = true
                        }
                    } else {
                        self.applyFilter = false
                    }
            }))
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM