Xcode Libraryにカスタムビューとモディファイアを追加する – WWDC2020

Session概要

利用可能なSwiftUIビューを見つけ、Xcode Previewsのキャンバスへドラッグ&ドロップし、リッチで視覚的なアプリの編集を可能にするのがXcode Libraryです。
自身のビューとモディファイアを使いXcode Libraryのコンテンツを拡大する方法、またアプリやSwiftパッケージ内で再利用性と発見性を最適化する方法について https://developer.apple.com/videos/play/wwdc2020/10649/

Xcode 12での新機能

  • Xcode 12ではSwiftUIビューとモディファイアをXcode Libraryに追加可能

Xcode Libraryの利点

  • 発見可能性
    • Libraryは開発者が利用可能なビジュアルコンテンツを探す場所で、重要で再使用可能なビューを配置し見つけやすくする
  • 習得しやすい
    • 各アセットはコンパイル可能な形で提供され、特定のビューやモディファイアの用途をコードのユーザに示すのに役立つ
  • ビジュアル編集
    • キャンバスにドラッグ&ドロップでき、Libraryからビューやモディファイアの插入でXcode Previewsがレンダリングを継続しリッチなビジュアル編集を可能にする
  • その他
    • 明示的にビルドせずともプロジェクトが実行可能でない場合でもコンテンツをLibraryに与えられる
    • Libraryコンテンツプロバイダコードは実行されないため、プロジェクトが配布用(release build)にビルドされた時、コンパイラが分離する

Xcode Libraryの拡張

  • LibraryContentProviderプロトコルに準拠した新しいタイプを宣言する必要がある
  • LibraryContentProviderプロトコルの要件
    • views Xcode Libraryの拡張に使用できる viewsプロパティ を追加する
    • モディファイアXcode Libraryの拡張に利用可能なモディファイアの関数 を追加する
public protocol LibraryContentProvider {
  @LibraryContentBuilder
  var views: [LibraryItem] { get }

  @LibraryContentBuilder
  public func modifiers(base: ModifierBase) -> [LibraryItem]
}

Libraryアイテムの作成方法

  • Libraryアイテムの作成にXcodeが求める最小データはユーザがアイテムを取得した時に插入される補完(下記サンプルでいうと、SmoothieRowView)
LibraryItem(
  SmoothieRowView(smoothie: .lemonberry),
  visible: true,  // 視認性
  title: "Smoothie Row View", // Libraryで検索しやすい + わかりやすい命名が良い
  category: .control // レイアウト、エフェクトなど
)

Libraryアイテムのカスタマイズオプション

同一のビューに相当した異なる設定の複数のLibraryアイテムの作成は合理的
struct LibraryContent: LibraryContentProvider {
    @LibraryContentBuilder
    var views: [LibraryItem] {
        LibraryItem(
            SmoothieRowView(smoothie: .lemonberry),
            category: .control
        )
        
        LibraryItem(
            SmoothieRowView(smoothie: .lemonberry, showNearbyPopularity: true),
            title: "Smoothie Row View With Popularity",
            category: .control
        )
    }
}

モディファイアLibraryの作成

下記のサンプルコードでは、width, heightを取得してアスペクト比を保ちつつ、指定された画面いっぱいに表示する
extension Image {
    func resizedToFill(width: CGFloat, height: CGFloat) -> some View {
        return self
            .resizable()
            .aspectRatio(contentMode: .fill)
            .frame(width: width, height: height)
    }
}
// 上記のImage Extension resizedToFillをモディファイアで使用するサンプル
@LibraryContentBuilder
    func modifiers(base: Image) -> [LibraryItem] {
        LibraryItem(
            base.resizedToFill(width: 100.0, height: 100.0) // width, heightは補完部分
        )
    }
最新情報をチェックしよう!