AdaptiveCardUI

CI Twitter: @gonzalezreal

AdaptiveCardUI 是一个用于在 SwiftUI 中渲染自适应卡片的库。

自适应卡片是用 JSON 编写的 UI 片段,应用程序和服务可以公开交换。 AdaptiveCardUI 将此 JSON 转换为原生 SwiftUI 视图树,从而可以将轻量级 UI 集成到您的 SwiftUI 应用程序中。

动机

Microsoft 构建并维护自适应卡片模式。 他们提供了适用于多个平台的 SDK,包括适用于 iOS 的 基于 UIKit Objective-C++ 的实现

AdaptiveCardUI 旨在为 Swift 开发者提供更自然的使用体验

自适应卡片基础

自适应卡片是清晰且一致地显示数据和与之交互的绝佳方式。 您可以使用它们来显示带有图像的富文本,允许用户与按钮交互,甚至收集表单数据。

这是一个简单的卡片,包含文本、图像和按钮。

{
  "type": "AdaptiveCard",
  "version": "1.3",
  "body": [
    {
      "type": "TextBlock",
      "text": "Here is very cute dog"
    },
    {
      "type": "Image",
      "url": "https://picsum.photos/id/237/300"
    }
  ],
  "actions": [
    {
      "type": "Action.OpenUrl",
      "url": "https://picsum.photos",
      "title": "Lorem Picsum Photos"
    }
  ]
}

根对象是自适应卡片本身,并指定显示它所需的 versionbody 由称为元素的构建块组成。 您可以以不同的方式排列它们以创建多种类型的卡片。 此外,自适应卡片可能包含用户可以操作的 actions

自适应卡片最基本的元素是

自适应卡片还可以具有容器,用于排列子元素的集合。

仅使用这些元素,您就可以设计具有相当复杂布局的自适应卡片。

iOSScreenshot MacOS Screenshot

自适应卡片可以使用 Input 元素收集表单数据。 AdaptiveCardUI 尚未渲染 Input 元素,但我们计划很快支持它们。

了解更多

显示自适应卡片

您可以通过提供自适应卡片所在的 URL 来创建自适应卡片视图。

AdaptiveCardView(url: URL(string: "https://adaptivecards.io/payloads/ActivityUpdate.json")!)

或者通过提供先前获取的自适应卡片。

let adaptiveCard = try JSONDecoder().decode(AdaptiveCard.self, from: jsonData)
...
AdaptiveCardView(adaptiveCard)

在显示卡片之前,视图会检查其版本是否受支持并异步下载其内容。

自定义外观

您可以通过提供配置来自定义自适应卡片的外观。 AdaptiveCardConfiguration 是一组值,用于指定库如何渲染不同的元素。 要为视图中的所有自适应卡片设置特定的配置,请使用 adaptiveCardConfiguration(_:) 修饰符。

 VStack {
     AdaptiveCardView(url: URL(string: "https://adaptivecards.io/payloads/ActivityUpdate.json")!)
     AdaptiveCardView(response.adaptiveCard)
 }
 .adaptiveCardConfiguration(AdaptiveCardConfiguration(...))

或者,您可以仅自定义自适应卡片外观的特定方面,例如操作或不同的间距值。 使用以下修饰符之一来自定义视图中所有自适应卡片的特定方面

添加自定义元素

自适应卡片是可扩展的,因此您可以添加自己的元素以及显示它们的视图。

例如,假设我们正在设计一张卡片来展示 GitHub 仓库的摘要。 其中一个元素是仓库语言,GitHub 使用一个填充了给定颜色的圆圈来表示它,旁边是语言名称。 该元素的 JSON 表示可能如下所示

{
  "type": "RepoLanguage",
  "horizontalAlignment": "center",
  "language": "Swift",
  "color": "#ffac45"
}

我们省略了继承的可选属性,例如 "id""isVisible""spacing""separator" 等。 但是您仍然需要支持它们。

要添加这个新元素,您需要创建一个符合 CustomCardElementCodableEquatable 的类型。

struct RepoLanguage: CustomCardElement, Codable, Equatable {
    // CustomCardElement

    @ItemIdentifier var id: String
    @Default<True> var isVisible: Bool
    @Default<False> var separator: Bool
    @Default<FirstCase> var spacing: Spacing
    @Default<Fallback.None> var fallback: Fallback<CardElement>
    @Default<EmptyDictionary> var requires: [String: SemanticVersion]

    // RepoLanguage

    @Default<FirstCase> var horizontalAlignment: HAlignment
    var language: String
    var color: String
}

如果您想知道,Default 属性包装器允许您为不需要的 JSON 属性提供默认值,从而消除大量的样板代码。 有关更多信息,请参见 DefaultCodable

由于新元素符合 CustomCardElement,您可以将其添加到自适应卡片、容器或列集中的列的主体中。 它将具有相对于前一个元素的间距和一个可选的分隔符。 除此之外,您可以为那些仍然不支持它的客户端提供回退元素。

请注意,您需要在任何自适应卡片解码发生之前注册新元素

CardElement.register(RepoLanguage.self)

您可以像创建任何其他 SwiftUI 视图一样创建渲染新元素的视图

struct RepoLanguageView: View {
    var repoLanguage: RepoLanguage

    var body: some View {
        HAlign(repoLanguage.horizontalAlignment) {
            Label {
                Text(repoLanguage.language)
            } icon: {
                Image(systemName: "circle.fill")
                    .imageScale(.small)
                    .foregroundColor(Color(argbHex: repoLanguage.color))
            }
        }
    }
}

最后,要将新元素及其视图与视图层次结构中的所有自适应卡片视图关联起来,请使用 customCardElement(_:, content:) 修饰符

VStack {
    AdaptiveCardView(url: URL(string: "https://adaptivecards.io/payloads/ActivityUpdate.json")!)
    AdaptiveCardView(response.adaptiveCard)
}
.customCardElement(RepoLanguage.self) {
    RepoLanguageView($0)
}

兼容性

AdaptiveCardUI 需要 Xcode 12 和 Swift 5.3。 它适用于 iOS 14.0 及更高版本。 如果您想尝试 macOS 支持,您需要安装 macOS Big Sur 11 和 Xcode 12.2。

安装

您可以通过将 AdaptiveCardUI 作为包依赖项添加到 Xcode 项目中。

  1. 文件菜单中,选择Swift Packages › Add Package Dependency…
  2. 在包存储库 URL 文本字段中输入 https://github.com/gonzalezreal/AdaptiveCardUI
  3. AdaptiveCardUI 链接到您的应用程序目标

其他库