Add interaction handlers to designs

In this section, we will learn how to add interactions to our design via interaction handlers.

NewsApp with tap interaction

Interaction handlers provide a way to specify where a component can be interacted with (tapped, double tapped, etc.). Interaction handlers can be added to any layer inside of a design.

Add handlers

Interaction handlers can be added to any layer. This allows designers to specify which parts of the component are interactive.

  1. Select the hero-item variant (the frame), click + next to the Parameter and select tap-handler to add an interaction handler. This allows developers to write code that reacts to a user tapping on the card.

    The Figma plugin with the hero-item variant selected
  2. Repeat the previous step with the menu icon layer in the audio-item variant. This allows developers to display a menu when a user taps on the menu icon.

    The Figma plugin with the menu icon variant selected
  3. If you select the on Menu tapped handler, you'll notice that it only applies to the audio-item variant, because the other variants do not have a menu icon. However, the on NewsCard tapped applies to all three variants. This means that you can supply one handler (in code) to run when any of the three variants are tapped, removing duplication of code and parameters. We’ll see how that works in more detail in the Update component in Android Studio section below.

    The Figma plugin with the tap handler selected

Save named version

Let’s now mark this version as ready to be imported into code.

  1. Add a new named version of your Figma file. Go to File > Save to Version History, and then enter a title and description of your new version (any title and description works here).

    Example Title: “Added Interactions”

    Example Description: “Two interaction handlers added to cards”

    Save to version history option in the menu

Update component in Android Studio

Let’s now update the NewsCard component:

  1. In Android Studio, make sure the Project tool window is in Android view. Then right-click on app/ui-packages/news_card/, and near the bottom of the context menu, click Update UI Package.

    Update UI Package option in the context menu
  2. Click on Make Project button to build your project. This takes the updated UI Package and generates an updated version of the composable code.

    Build button in the toolbar
  3. If you look at app/java/com/example/hellonews/newscard/NewsCard.kt, you’ll see that the interaction handlers are added as parameters to NewsCard (onNewsCardTapped, onMenuTapped).

    // 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(
        onNewsCardTapped: () -> Unit = {},
        thumbnail: Painter,
        headline: String,
        author: String,
        date: String,
        onMenuTapped: () -> Unit = {},
        modifier: Modifier = Modifier,
        view: View = View.HeroItem
    ) {
    ...
    

Integrate into app

Now let’s add some handlers to our interactions.

  1. In app/java/com/example/hellonews/ui/home/HomeScreen.kt, scroll down to PostListArticleStories, around line 175.

    ...
    @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. For postTop, add handlers for onNewsCardTapped and onMenuTapped. createOnTapped opens a dialog with its parameters as the title and body.

    @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),
                onMenuTapped = {},
                view = View.HeroItem
            )
            Spacer(modifier = Modifier.size(12.dp))
            ...
        }
    }
    
  3. For each post, add handlers for onNewsCardTapped and onMenuTapped.

    @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),
                    onMenuTapped = {},
                    view = View.ArticleItem
                )
                Spacer(modifier = Modifier.size(12.dp))
            }
        }
    }
    
  4. Still in HomeScreen.kt, scroll down to PostListAudioStories, around line 260.

    ...
    @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. For each post, add handlers for onNewsCardTapped and onMenuTapped. Since the Audio variant does have a menu, we also assign createOnTapped to 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. Click ▶ to build the app and run it in the emulator.

    Run button in toolbar
    News app in action in preview

    Hooray! You've learned the advanced features of Relay.

You can learn more about how to work with Relay in the Relay Workflow section. We’d also love to hear from you if you have any feedback.