在设计中添加互动处理程序

在本部分中,我们将学习如何通过互动处理程序在设计中添加互动体验。

提供点按互动体验的新闻应用

互动处理程序可让您指定组件提供互动体验(点按、点按两次等)的位置。您可以在设计中的任意层添加互动处理程序。

添加处理程序

您可以在任意层添加互动处理程序。这样,设计人员就可以指定组件的哪些部分具有互动性。

  1. 选择 hero-item 变体(即框架),点击 Parameter 旁边的 +,然后选择 tap-handler 以添加互动处理程序。这样,开发者就可以编写代码来回应用户点按卡片的操作。

    选择了 hero-item 变体的 Figma 插件
  2. audio-item 变体中的 menu 图标层重复上一个步骤。这可让开发者在用户点按菜单图标时显示菜单。

    选择了菜单图标变体的 Figma 插件
  3. 如果您选择 on Menu tapped 处理程序,则会发现该选项仅应用于 audio-item 变体,因为其他变体没有菜单图标。不过,on NewsCard tapped 会应用于所有三个变体。这意味着,您可以(在代码中)提供一个处理程序,以便在点按三个变体中的任何一个时运行,从而消除重复的代码和参数。如需详细了解其工作原理,请参阅下面的在 Android Studio 中更新组件部分。

    选择了点按处理程序的 Figma 插件

保存已命名的版本

现在,将此版本标记为准备就绪,以便导入代码中。

  1. 打开 Figma Relay 插件(如果尚未打开)。

  2. 点击对话框右下角的“与开发者共享”。

  3. 与开发者共享屏幕上,输入版本的名称和说明。

    标题示例:增加的互动

    说明示例:向卡片中添加了两个互动处理程序

  4. 点击保存

  5. 若要将组件链接复制到剪贴板,请在 MAC 上按 CMD-L,在 Windows 上按 CTRL-L

在 Android Studio 中更新组件

现在,让我们更新 NewsCard 组件:

  1. 在 Android Studio 中,确保“Project”工具窗口处于 Android 视图中。然后右键点击 app/ui-packages/news_card/,并点击上下文菜单底部附近的 Update UI Package

    上下文菜单中的“Update UI Package”选项
  2. 点击 “Make Project”按钮 以构建您的项目。该操作将采用更新后的界面软件包,并生成可组合代码的更新版本。

    工具栏中的“Build”按钮
  3. 查看 app/java/com/example/hellonews/newscard/NewsCard.kt 并看到互动处理程序是以参数的形式添加到 NewsCardonNewsCardTappedonMenuTapped)。

    // Design to select for NewsCard
    enum class View {
      HeroItem, ArticleItem, AudioItem
    }
    
    /**
    *   Displays a summary of a news article.
    *
    *   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 = EmptyPainter(),
      headline: String = "",
      author: String = "",
      date: String = "",
      onNewsCardTapped: () -> Unit = {},
      onMenuTapped: () -> Unit = {}
    ) {
    ...
    

集成到应用中

现在,我们来为互动添加一些处理程序。

  1. app/java/com/example/hellonews/ui/home/HomeScreen.kt 中,向下滚动到第 175 行左右的 PostListArticleStories

    ...
    @Composable
    fun HomeScreen(...)
    
    @Composable
    private fun PostList(...)
    
    @Composable
    private fun PostListArticleStoriesSection(...)
    
    @Composable
    private fun SearchArticlesSection(...)
    
    @Composable
    private fun PostListArticleStories(
      postTop: Post,
      posts: List<Post>,
      createOnTapped: (String, String) -> () -> Unit
    ) {...}
    
    @Composable
    private fun AudioStoriesTitle(...)
    
    @Composable
    private fun PostListAudioStories(...)
    
    @Composable
    fun Dialog(...)
    ...
    
  2. 对于 postTop,请为 onNewsCardTapped 添加处理程序。createOnTapped 会打开一个对话框,其参数将作为标题和正文。

    @Composable
    private fun PostListArticleStories(
      postTop: Post,
      posts: List<Post>,
      createOnTapped: (String, String) -> () -> Unit
    ) {
      ...
      Column(
          horizontalAlignment = Alignment.Start,
          modifier = ...
      ) {
          Spacer(modifier = Modifier.size(12.dp))
          NewsCard(
              thumbnail = painterResource(postTop.imageId),
              headline = postTop.title,
              author = postTop.metadata.author.name,
              date = postTop.metadata.date,
              onNewsCardTapped = createOnTapped("Card Tapped", postTop.title),
              view = View.HeroItem
          )
          Spacer(modifier = Modifier.size(12.dp))
          ...
      }
    }
    
  3. 针对每个 post,为 onNewsCardTapped 添加处理程序。

    @Composable
    private fun PostListArticleStories(
      postTop: Post,
      posts: List<Post>,
      createOnTapped: (String, String) -> () -> Unit
    ) {
      ...
      Column(
          horizontalAlignment = Alignment.Start,
          modifier = ...
      ) {
          ...
    
          posts.forEach { post ->
              NewsCard(
                  thumbnail = painterResource(post.imageId),
                  headline = post.title,
                  author = post.metadata.author.name,
                  date = post.metadata.date,
                  onNewsCardTapped = createOnTapped("Card Tapped", post.title),
                  view = View.ArticleItem
              )
              Spacer(modifier = Modifier.size(12.dp))
          }
      }
    }
    
  4. 同样在 HomeScreen.kt 中,向下滚动到第 260 行左右的 PostListAudioStories

    ...
    @Composable
    fun HomeScreen(...)
    
    @Composable
    private fun PostList(...)
    
    @Composable
    private fun PostListArticleStoriesSection(...)
    
    @Composable
    private fun SearchArticlesSection(...)
    
    @Composable
    private fun PostListArticleStories(...)
    
    @Composable
    private fun AudioStoriesTitle(...)
    
    @Composable
    private fun PostListAudioStories(
      posts: List<Post>,
      createOnTapped: (String, String) -> () -> Unit
    ) {...}
    
    @Composable
    fun Dialog(...)
    ...
    
  5. 针对每个 post,为 onNewsCardTapped 添加处理程序。由于 Audio 变体具有菜单,因此请将 createOnTapped 分配给 onMenuTapped

    @Composable
    private fun PostListAudioStories(
      posts: List<Post>,
      createOnTapped: (String, String) -> () -> Unit
    ) {
      Column(
          horizontalAlignment = ...,
          modifier = ...
      ) {
          posts.forEach { post ->
              NewsCard(
                  thumbnail = painterResource(post.imageId),
                  headline = post.title,
                  author = post.metadata.author.name,
                  date = post.metadata.date,
                  onNewsCardTapped = createOnTapped("Card Tapped", post.title),
                  onMenuTapped = createOnTapped("Menu Tapped", post.title),
                  view = View.AudioItem
              )
              Spacer(modifier = Modifier.size(12.dp))
          }
      }
    }
    
  6. 点击 ▶ 即可构建应用,并在模拟器中运行该应用。

    工具栏中的“Run”按钮
    新闻应用在预览中的实际运行情况

    太棒了!您已经了解 Relay 的高级功能。

如需详细了解如何使用 Relay,请参阅 Relay 工作流部分。如果您有任何反馈,也欢迎与我们分享。