簡體   English   中英

為什么當我通過@AppStorage 存儲列表項目時添加項目后,我的選擇有時不會在 macOS SwiftUI 列表中突出顯示

[英]Why sometimes my selection doesn't get highlighted in macOS SwiftUI List after I've added an item when List items are stored through @AppStorage

我似乎找不到我做錯了什么。

這是設置:

  1. 通過 AppStorage 存儲為 Set 的捆綁標識符
  2. 通過 drop 添加的新包標識符

問題如下:

  1. 正常情況:項目被選中、突出顯示和上下文刪除可用(顯示項目被選中)

在此處輸入圖像描述

  1. 正常情況:項目未選中、未突出顯示、上下文刪除不可用

在此處輸入圖像描述

  1. 問題:項目被選中但未突出顯示,並且上下文可用(顯示項目已被選中)

在此處輸入圖像描述

這個問題可能發生在 80% 的時間里,並非總是如此。 當我將新項目添加到列表中時會發生這種情況,並且我選擇了該項目而沒有先單擊列表中的任何其他位置。 如果我先單擊另一個項目,或者在列表中沒有項目的空間中單擊,則在之后選擇新項目將正常工作,並且該項目將突出顯示。 這讓我覺得這可能是一個國家問題? 但我找不到我做錯的地方。

這是代碼:

import SwiftUI


// to save Sets through AppStorage
extension Set: RawRepresentable where Element: Codable {

    public init?(rawValue: String) {
        guard let data = rawValue.data(using: .utf8) else { return nil }
        guard let result = try? JSONDecoder().decode(Set<Element>.self, from: data) else { return nil}
        
        self = result
    }

    public var rawValue: String {
        guard let data = try? JSONEncoder().encode(self) else { return "[]" }
        guard let result = String(data: data, encoding: .utf8) else { return "[]" }
        
        return result
    }
    
}


struct ContentView: View {
    
    @AppStorage("apps") var apps: Set<String> = []
    @State private var appsSelection: Set<String> = []
    
    var body: some View {
        
        Form {
            List(Array(apps), id: \.self, selection: $appsSelection) { app in
                Text(app)
            }
            .contextMenu {
                Button("Delete") {
                    for selection in appsSelection {
                        apps.remove(selection)
                    }
                }
                .disabled(appsSelection.isEmpty)
            }
            .onDeleteCommand {
                for selection in appsSelection {
                    apps.remove(selection)
                }
            }
            .listStyle(.bordered(alternatesRowBackgrounds: true))
            .onDrop(of: [.fileURL], delegate: AppsDropDelegate(apps: $apps))
        }

    }
        
}


// the DropDelegate
private struct AppsDropDelegate: DropDelegate {

    @Binding var apps: Set<String>


    func validateDrop(info: DropInfo) -> Bool {
        guard info.hasItemsConforming(to: [.fileURL]) else { return false }

        let providers = info.itemProviders(for: [.fileURL])
        var result = false

        for provider in providers {
            if provider.canLoadObject(ofClass: URL.self) {
                let group = DispatchGroup()
                group.enter()

                _ = provider.loadObject(ofClass: URL.self) { url, _ in
                    let itemIsAnApplicationBundle = try? url?.resourceValues(forKeys: [.contentTypeKey]).contentType == .applicationBundle
                    result = result || (itemIsAnApplicationBundle ?? false)
                    group.leave()
                }
                                
                _ = group.wait(timeout: .now() + 0.5)
            }
        }

        return result
    }

    func performDrop(info: DropInfo) -> Bool {
        let providers = info.itemProviders(for: [.fileURL])
        var result = false

        for provider in providers {
            if provider.canLoadObject(ofClass: URL.self) {
                let group = DispatchGroup()
                group.enter()

                _ = provider.loadObject(ofClass: URL.self) { url, _ in
                    let itemIsAnApplicationBundle = (try? url?.resourceValues(forKeys: [.contentTypeKey]).contentType == .applicationBundle) ?? false

                    if itemIsAnApplicationBundle, let url = url, let app = Bundle(url: url), let bundleIdentifier = app.bundleIdentifier {
                        DispatchQueue.main.async {
                            apps.insert(bundleIdentifier)
                        }
                        
                        result = result || true
                    }
                                        
                    group.leave()
                }

                _ = group.wait(timeout: .now() + 0.5)
            }
        }
        
        return result
    }
    
}

提前致謝。

好的,經過更多測試,這似乎是一個 SwiftUI 錯誤。 可能與@AppStorage 的緩存機制有關,因為它不會即時從磁盤寫入/讀取。 SwiftUI 有時會發布更新,有時不會。 這已向 Apple 報告為 FB10029588。 此處的示例項目: https ://github.com/godbout/ListDrop。

解決這個問題的方法是手動更新選擇。 為此,我創建了一個@ObservableObject ,它通過@AppStorage 處理項目列表,並通過@Published 屬性處理選擇。 刪除選擇時,我手動將屬性設置為空。 這確實解決了問題。 下次添加項目時,它們會在選中時突出顯示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM