带有泛型的 contextMenu 的 SwiftUI ViewModifier

问题描述 投票:0回答:1

我想为'contextMenu forSelectionType: menu:'添加iOS16 API,但我还需要支持iOS15,所以我需要一个条件

ViewModifier
。我正在努力寻找正确的语法。

据我所知,我的

ViewModifier
应该是这样的:

struct CompatibilityListContextMenuModifier<V>: ViewModifier where V: View {

    let menu: (Set<Person.ID>) -> V
    
    func body(content: Content) -> some View {
      if #available(iOS 16.0, macOS 13.0, *) {
          content
              .contextMenu(forSelectionType: Person.ID.self, menu: menu)
        } else {
            content
        }
    }
}

但是我如何在我的列表中使用它:

List (selection: $contactsListOptions.multiSelectedContacts){
   // ...
}
.modifier(CompatibilityListContextMenuModifier(menu: items in {
            if items.isEmpty { // Empty area menu.
                Button("New Item") { }

            } else if items.count == 1 { // Single item menu.
                Button("Copy") { }
                Button("Delete", role: .destructive) { }
            }
            else {
                Button("MultipleSelection Items") { }
            }
        }))

这给了我一个语法错误:

在范围内找不到“项目”

如果我尝试传入选择绑定:

.modifier(CompatibilityListContextMenuModifier(menu: contactsListOptions.multiSelectedContacts in {
        if contactsListOptions.multiSelectedContacts.isEmpty { // Empty area menu.
            Button("New Item") { }

        } else if contactsListOptions.multiSelectedContacts.count == 1 { // Single item menu.
            Button("Copy") { }
            Button("Delete", role: .destructive) { }
        }
        else {
            Text("MultipleSelection Items")
        }
    }))

我收到错误:

无法将“Set”类型(又名“Set”)的值转换为 预期参数类型 '(Set) -> V' (又名 '(Set) -> V')

无法推断通用参数“V”

条件编译此 API 的正确方法是什么?

swiftui viewmodifier
1个回答
0
投票

创建修饰符的语法应该是:

CompatibilityListContextMenuModifier { items in ... }

闭包参数应位于

{ ... }
内部。

闭包也应该是一个

@ViewBuilder
,否则你不能在闭包中使用像这样的
if
语句。

// I also abstracted away Person.ID as the Selection type parameter
struct CompatibilityListContextMenuModifier<Menu, Selection>: ViewModifier
    where Menu: View, Selection: Hashable {

    @ViewBuilder
    let menu: (Set<Selection>) -> Menu
    
    func body(content: Content) -> some View {
      if #available(iOS 16.0, macOS 13.0, *) {
          content
              .contextMenu(forSelectionType: Selection.self, menu: menu)
        } else {
            content
        }
    }
}

现在你可以像这样使用它:

.modifier(CompatibilityListContextMenuModifier<_, Person.ID> { items in
    if items.isEmpty {
        Button("New Item") { }

    } else if items.count == 1 {
        Button("Copy") { }
        Button("Delete", role: .destructive) { }
    }
    else {
        Button("MultipleSelection Items") { }
    }
})

我还建议您编写自己的

View
扩展,以便更方便地编写此内容:

extension View {
    func compatibilityContextMenu<Menu: View, Selection: Hashable>(
        forSelectionType type: Selection.Type, 
        @ViewBuilder menu: @escaping (Set<Selection>) -> Menu
    ) -> some View {
        modifier(CompatibilityListContextMenuModifier(menu: menu))
    }
}
.compatibilityContextMenu(forSelectionType: Person.ID.self) { items in
    // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.