UI パッケージと生成されたコードを理解する

UI パッケージ

UI パッケージは、UI 情報を交換するための新しい柔軟な方法です。デザイナーは、Relay for Figma プラグインを使用して、Figma のコンポーネントから UI パッケージを作成します。これを行うと、デベロッパーが使用できるデザインが宣言されます。その後、デザイナーが Figma デザイン ファイルの URL をデベロッパーに提供します。

デベロッパーは Android Studio プラグインを使用して、Figma デザイン ファイルから UI パッケージをインポートします。Android Studio プロジェクトでは、UI パッケージに、インポートされた Figma コンポーネントの宣言型の説明と、フォント ファイル、画像、SVG などの関連するアセットが含まれます。

UI パッケージは永続的なアーティファクトであり、ソース管理に commit できます。デベロッパーが Android Studio プロジェクトに Figma パッケージをインポートすると、ファイルは ui-packages フォルダ内のプロジェクトに追加されます。以下に、インポートされた UI パッケージの例を示します。

<ph type="x-smartling-placeholder">
</ph> UI パッケージの内容

インポートされた UI パッケージを含むプロジェクトには、次のファイルが含まれます。

  • [component_name].json - コンポーネントを記述する JSON ファイル(たとえば、story_card.json)。
  • config.json - 特定の UI パッケージのメタデータを保存します。
  • fonts/ - コンポーネントで使用されるフォント アセットが保存されているフォルダ(存在する場合)。
  • *.png - menu.png などコンポーネントで使用される画像アセット(ある場合)。
  • [component_name]_preview.png - コンポーネントのプレビュー画像( 例: story_card_preview.png)。
  • *.svg - 三角形など、コンポーネントで使用されるベクター グラフィック アセット(ある場合)。
  • FONTS.txt - 使用されているフォントのリスト(ある場合)。
  • DEPS.txt - 子コンポーネントの名前。
  • VERSION.txt - UI の作成とインポートに使用される Relay のバージョン パッケージ。

これらは src/main/ui-packages/[package_name] に保存されます。

UI パッケージの削除

プロジェクトから UI パッケージを削除するには、ui-packages/ にあるフォルダを削除します。フォルダの削除後にプロジェクトを再構築すると、生成されたコードも削除されます。

生成されたコードフォルダ構造

プロジェクトがビルドされると、これらの UI パッケージは、デベロッパーが呼び出せる @Composable 関数を含む、生成されたコードに変換されます。これらは build/generated/ に保存されます。Android ビューでは、モジュール ディレクトリ(この場合は app ディレクトリ)に java (generated) および res として表示されます。

Android Studio で生成されたファイルを含むフォルダ

次のスクリーンショットは、このディレクトリ内のファイルを示しています。

  • フォントや画像などのリソースは build/generated/res/relay/ にコピーされます。

    res フォルダに生成されたリソース
  • 各 UI パッケージで、生成されたコードが build/generated/source/relay/ に配置されます。各 UI パッケージの生成されたコードフォルダには、 インポートされたコンポーネントに対応する単一のファイルが作成されます。また、 末尾が Fonts.kt の単一のファイルがあり、このファイルには以下への参照が含まれます。 使用されるフォント アセットを定義します。

    java(generated) フォルダに生成された Kotlin ファイル
  • ランタイム ライブラリ com.google.relay.compose もあり、生成されたコードで使用する機能を提供します。

    Relay ランタイム ライブラリ
で確認できます。

生成されたコード構造

コンポーザブル

Figma のコンポーネントはレイヤで構成されています。たとえば、このデザインにはフレームレイヤ Hello Card が含まれており、このレイヤには 2 つの子レイヤ、Image(画像レイヤ)とTitle(テキストレイヤ)が含まれます。

画像レイヤとタイトルレイヤを持つ Hello Card コンポーネント

このデザインをコードに変換する場合、レイヤごとに個別のコンポーズ可能な関数が作成されます。ここで、Figma レイヤの名前はコンポーズ可能な関数の名前です(Kotlin 構文に合わせて変更されます)。レイヤは次のように変換されます。

  1. Hello Card レイヤ:

    @Composable
    fun HelloCard(
      modifier: Modifier = Modifier,
      title: String
    ) {
      TopLevel(modifier = modifier) {
          Image()
          Title(title = title)
      }
    ]
    
  2. Image レイヤ:

    @Composable
    fun Image(modifier: Modifier = Modifier) {
      Image(...)
    }
    
  3. Title レイヤ:

    @Composable
    fun Title(
      title: String,
      modifier: Modifier = Modifier
    ) {
      Text(...)
    }
    

変換後の Figma のバリアントとパラメータ

Figma コンポーネントに複数のバリアントがある場合、生成されるコードには、各バリアント プロパティの列挙型が含まれます。各バリアント列挙型の値は、そのバリアント プロパティの値に対応しています。コンポーザブルには、各バリアント列挙型のパラメータが含まれます。

// Design to select for NewsCard
enum class View {
    HeroItem,
    ArticleItem,
    AudioItem
}

/**
 *   This composable was generated from the UI Package 'news_card'.
 *   Generated code; do not edit directly
 */
@Composable
fun NewsCard(
    modifier: Modifier = Modifier,
    view: View = View.HeroItem,
    onNewsCardTapped: () -> Unit = {},
    thumbnail: Painter,
    headline: String,
    author: String,
    date: String,
    onMenuTapped: () -> Unit = {}
) {
       when (view) {
           View.HeroItem -> TopLevelViewHeroItem(...) {
               ContentViewHeroItem { ... }
           }
           View.ArticleItem -> TopLevelViewArticleItem(...) {
               ContentViewArticleItem { ... }
           }
           View.AudioItem -> TopLevelViewAudioItem(...) {
               ContentViewAudioItem { ... }
           }
       }
   }
}

Figma コンポーネントの各コンテンツ パラメータとインタラクション ハンドラは、コンポーザブルのパラメータに変換されます。以下の NewsCard コンポーザブルには、4 つのコンテンツ パラメータ(1 つの画像と 3 つの文字列)と 2 つのインタラクション ハンドラ(最後の 2 つのパラメータ)があります。

/**
 *   This composable was generated from the UI Package 'news_card'.
 *   Generated code; do not edit directly
 */
@Composable
fun NewsCard(
    modifier: Modifier = Modifier,
    view: View = View.HeroItem,
    thumbnail: Painter,
    headline: String,
    author: String,
    date: String,
    onNewsCardTapped: () -> Unit = {},
    onMenuTapped: () -> Unit = {}
) {...}