9.3 提供搜索词建议

原文链接: https://developer.apple.com/documentation/swiftui/suggesting-search-terms

9.3 提供搜索词建议

向在应用中搜索内容的人提供建议。

概述

你可以通过提供一组搜索建议视图,在搜索过程中建议查询文本。由于建议视图并不限于纯文本,你还必须提供每个建议视图所代表的搜索字符串。如果你的搜索界面包含令牌,你也可以为令牌提供建议。SwiftUI 会把建议显示在搜索框下方的列表中。

一个圆角宽矩形,带蓝色描边,左边是放大镜,右边是灰色的 Search 文本。矩形下方出现另一个带投影的矩形列表。列表包含三项,每项由一个词和展示对应图像的 emoji 组成。这三项是 Apple、Pear 和 Banana。

对文本和令牌来说,建议列表都由你自己管理,因此你可以完全自由地决定建议什么。例如,你可以:

  • 提供一份静态的建议列表。
  • 记住先前的搜索,提供最近的或最常用的建议。
  • 根据当前搜索文本实时更新建议列表。
  • 组合使用上述策略和其他策略,并可能随时间调整。

建议搜索文本

通过向 searchSuggestions(_:) 视图修饰符提供一组视图,来建议搜索文本。这个修饰符作用于出现在它之前的 searchable(text:placement:prompt:) 修饰符。

当有人激活搜索界面时,它会把建议视图作为查询字符串下方的一组选项呈现出来。在搜索建议闭包内,给视图添加 searchCompletion(_:) 修饰符,就能把字符串与每个建议视图关联起来。例如,你可以在建议搜索的水果商品类型中加入 emoji,并为每种情况提供对应的搜索字符串作为搜索补全:

1
2
3
4
5
6
7
ProductList(departmentId: departmentId, productId: $productId)
    .searchable(text: $model.searchText)
    .searchSuggestions {
        Text("🍎 Apple").searchCompletion("apple")
        Text("🍐 Pear").searchCompletion("pear")
        Text("🍌 Banana").searchCompletion("banana")
    }

当有人选择某个建议时,SwiftUI 会用搜索补全字符串替换搜索框中的文本。在上面的例子中,选择 “🍐 Pear” 会把文本 “pear” 放入搜索查询。

一个带三个导航窗格的 macOS 窗口。左侧窗格列出 Produce、Frozen 和 Bakery 三项。中间窗格是一长串水果和蔬菜。右侧窗格显示占位文本 Select a Product。工具栏在窗口右上角有一个搜索框,占位文本为 Search。搜索框上附着一个浮在窗口上方的列表。列表包含 Apple、Pear 和 Banana 三项,每项由一个 emoji 和对应文本组成。

如果你省略了某个建议视图的搜索补全修饰符,SwiftUI 仍会显示该视图,但它不会响应轻点或点击。不过,你可以用带页眉的 Section 容器把视图分组,从而区分不同种类的建议,例如最近的搜索和常用搜索词。

重要:在 tvOS 中,searchable 修饰符只支持 Text 类型的建议视图,如上面的例子所示。其他平台可以使用任意视图作为建议,包括自定义视图。

某些事件或操作(例如有人移动 macOS 窗口)可能会关闭建议列表。

建议令牌

你也可以为搜索框建议令牌。这种情况下,使用接收令牌作为输入的 searchCompletion(_:) 修饰符版本,把建议视图与令牌关联起来:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ProductList(departmentId: departmentId, productId: $productId)
    .searchable(text: $model.searchText, tokens: $model.tokens) { token in
        switch token {
        case .apple: Text("Apple")
        case .pear: Text("Pear")
        case .banana: Text("Banana")
        }
    }
    .searchSuggestions {
        Text("Apple").searchCompletion(FruitToken.apple)
        Text("Pear").searchCompletion(FruitToken.pear)
        Text("Banana").searchCompletion(FruitToken.banana)
    }

你可以使用任何遵循 Identifiable 协议的类型作为令牌。关于在搜索查询中使用令牌的更多信息,参见执行搜索操作。

简化令牌建议

当你的建议集合与令牌列表完全一致时,为了简化操作,你可以创建一个可建议的候选令牌集合。例如,你可以在模型中添加一个已发布的 suggestions 属性,包含所有可能的令牌:

1
@Published var suggestions: [FruitToken] = FruitToken.allCases

然后把这个数组提供给接收 suggestedTokens 输入参数的某个 searchable 修饰符,例如 searchable(text:tokens:suggestedTokens:placement:prompt:token:)。SwiftUI 会用它自动生成建议:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ProductList(departmentId: departmentId, productId: $productId)
    .searchable(
        text: $model.searchText,
        tokens: $model.tokens,
        suggestedTokens: $model.suggestions
    ) { token in
        switch token {
        case .apple: Text("Apple")
        case .pear: Text("Pear")
        case .banana: Text("Banana")
        }
    }

在这个版本的 searchable 修饰符中,SwiftUI 用同一个内容构建器来描述令牌在搜索框和建议容器中的外观。

动态更新建议

你可以随着条件变化更新所提供的建议。例如,你可以指定一个存储在应用模型中的 suggestedSearches 数组:

1
2
3
4
5
6
7
8
ProductList(departmentId: departmentId, productId: $productId)
    .searchable(text: $model.searchText)
    .searchSuggestions {
        ForEach(model.suggestedSearches) { suggestion in
            Label(suggestion.title,  image: suggestion.image)
                .searchCompletion(suggestion.text)
        }
    }

如果 suggestedSearches 一开始是空数组,界面最初不会显示任何建议。随后你可以随着条件变化更新这个数组,例如在其中加入先前的搜索记录。