了解界面软件包和生成的代码

界面软件包

界面软件包是一种交换界面信息的全新灵活方式。设计人员使用 Relay for Figma 插件,借助 Figma 中的组件创建界面软件包。这样做,即表示设计已准备就绪,可供开发者使用。然后,设计人员向开发者提供其 Figma 设计文件的网址。

开发者使用 Android Studio 插件从 Figma 设计文件导入界面软件包。在 Android Studio 项目中,界面软件包包含导入的 Figma 组件的声明性说明以及关联的资源,包括字体文件、图片和 SVG。

界面软件包是持久性工件,可以提交到源代码控制系统。当开发者在 Android Studio 项目中导入 Figma 软件包时,文件会添加到项目的 ui-packages 文件夹内。以下是导入的界面软件包的示例:

界面软件包的内容

使用导入的界面软件包的项目包含以下文件:

  • [component_name].json - 一个描述组件的 JSON 文件(例如 story_card.json)。
  • config.json - 用于存储特定界面软件包的元数据。
  • fonts/ - 一个存储组件使用的字体资源(如果有)的文件夹。
  • *.png - 组件中使用的图片素材资源(如果有),例如 menu.png
  • [component_name]_preview.png - 组件的预览图片(例如 story_card_preview.png)。
  • *.svg - 组件中使用的矢量图形资源(如果有),例如三角形。
  • FONTS.txt - 使用的字体(如果有)的列表。
  • DEPS.txt - 任何子组件的名称。
  • VERSION.txt - 用于创建和导入界面软件包的 Relay 版本。

这些文件存储在 src/main/ui-packages/[package_name] 下。

移除界面软件包

如需从项目中移除界面软件包,您可以删除 ui-packages/ 下的文件夹。移除文件夹后重新构建项目,会同时移除其生成的代码。

生成的代码文件夹结构

在项目构建时,这些界面软件包会转换为生成的代码,其中包含开发者可以调用的 @Composable 函数。这些代码存储在 build/generated/ 下。在“Android”视图中,这些代码在模块目录(在本例中为 app 目录)下显示为 java (generated)res

Android Studio 中包含生成的文件的文件夹

以下屏幕截图展示了此目录中的文件:

  • 字体和图片等资源会复制到 build/generated/res/relay/

    res 文件夹下的生成的资源
  • 每个界面软件包都有生成的代码,位于 build/generated/source/relay/ 下。每个界面软件包的生成的代码文件夹都有一个与已导入的组件对应的单个文件。它还包含以 Fonts.kt 结尾的单个文件,其中包含对组件使用的字体资源的引用。

    java(generated) 文件夹下的生成的 Kotlin 文件
  • 此外,还有一个运行时库 com.google.relay.compose,它提供生成的代码所使用的功能。

    Relay 运行时库

生成的代码结构

可组合项

Figma 中的组件由多个层组成。例如,以下设计包含一个帧层 Hello Card,该帧层包含两个子层:Image(图片层)和 Title(文本层):

包含 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 可组合项有四个内容参数(一个图片和三个字符串)和两个交互处理程序(最后两个参数)。

/**
 *   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 = {}
) {...}