avatarBenjamin Baxter

Summary

The web content provides guidance on customizing the Android TV Leanback library to display circular avatars instead of the default rectangular cards, including the removal of default shadows and the addition of custom borders.

Abstract

The article "Customizing Leanback for Android TV" discusses how developers can modify the Leanback library's default UI components to better suit non-rectangular content, such as circular avatars for movie cast members. It explains the use of Glide's circleCropTransform() to create circular images and details how to disable the default drop shadows and dimming effects on selected and inactive rows using ListRowPresenter. The article also suggests adding a border to selected cards for better visual distinction, providing code snippets and XML examples for implementing these customizations. The author emphasizes the importance of understanding the impact of padding and margins on the layout and encourages developers to share their own Leanback customization experiences.

Opinions

  • The author believes that circular avatars are a superior design choice for displaying people, as opposed to the default rectangular cards provided by the Leanback library.
  • There is an opinion that removing shadows and adding borders can enhance the user experience by making the selected card more noticeable, especially when the default shadows do not match the circular design.
  • The author suggests that disabling the default dimming effect for inactive rows can improve the UI but also cautions that it may make it harder for users to determine which card is selected.
  • The article conveys that customizing the Leanback library can be done with relatively few lines of code, showcasing the flexibility of the library for building UIs for Android TV.
  • There is an implicit opinion that developers should be mindful of the layout bounds and the effects of padding and margins when customizing UI components to achieve the desired visual results.
  • The author encourages community engagement and knowledge sharing by inviting developers to discuss their Leanback customization use cases and experiences.

Customizing Leanback for Android TV

Putting round pegs in square holes

The leanback library provides a templated UI so developers can focus on the important parts of their app.

When using leanback, content is shown in rows. Leanback supplies a rectangular card view, ImageCardView, to easily display content. The card size scales when selected and has shadows to accent the content. This is great for content such as movie posters and album art.

Movie posters work great with the default leanback behavior

Sometimes it is a better design to show content in other ways than a rectangle. For example, when displaying the cast of a movie, it is better to use a circular avatar design (round peg, get it?). This is a pretty common design for displaying avatars.

Circular avatars are great for displaying people

In this article we are going to dive into how to customize a card view to be a circle instead of the default square and configure the drop shadows and dimming effects.

Creating a Circular Image

There are many ways to apply circular bounds to an image. If you use Glide, this is as simple as calling circleCropTransform().

val requestOptions = RequestOptions
                    .circleCropTransform()
Glide.with(context)
            .load(personImage)
            .apply(requestOptions)
            .into(vh.personImageView)

Depending on the library, your mileage may vary.

Disabling Selected Shadow

Even though the image is circular, leanback adds drop shadows which do not match the circular image. We need to customize leanback to disable the drop shadows.

ListRowPresenter adds a shadow around each card when selected. It also controls the style of the row and the interactions between cards in a row.

You can disable shadows by setting the shadowEnabled flag to false. This tells leanback not to add a shadow around the selected card.

val customListRowPresenter = object : ListRowPresenter().apply {
    shadowEnabled = false
}

The picture below shows the selected card with its shadow:

The shadow disappears when you set the value of `shadowEnabled` false:

However, there is still a shadow when the row is inactive. The shadow is more noticeable when the image is circular as shown in the image below. Next we will remove that shadow.

Active and Inactive Rows

By default, when the user selects a row, other rows are dimmed. This effect is controlled by ListRowPresenter.

There is a method in ListRowPresenter that can be overridden to disable the effect. Extend the presenter and override isUsingDefaultListSelectEffect() to return false.

val customListRowPresenter = object : ListRowPresenter() {
    override fun isUsingDefaultListSelectEffect() = false
}

This removes the shadow effect from the inactive rows.

Please be careful. When you disable the dimming of inactive rows it becomes quite hard to determine which card is selected.

Putting it all together

Customizing ListRowPresenter with just a few lines of code can remove the shadowing effects and allow us to build a custom user experience with leanback components.

val customListRowPresenter = object : ListRowPresenter() {
        override fun isUsingDefaultListSelectEffect() = false
    }.apply {
        shadowEnabled = false
    }

Adding borders to the selected card

When you’ve removed shadows, you can make a selected card more noticeable by adding a border. It is clear that the third person is selected in the picture below.

If you use a custom view for the card, add a border to the layout.

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="8dp">
    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/imageBackground"
        android:background="@drawable/bg_avatar_border"
        android:padding="4dp">
        <ImageView
            android:id="@+id/personImage"
            android:layout_width="@dimen/card_avatar_width"
            android:layout_height="@dimen/card_avatar_width"
            android:adjustViewBounds="true"
           />
    </FrameLayout>
</FrameLayout>

Add a background to the view surrounding the image view. The background should be a selector that sets the background when selected and removes it otherwise.

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true"
        android:drawable="@drawable/bg_avatar" />
    <item android:state_selected="false"
        android:drawable="@android:color/transparent" />
</selector>

In this example, an oval drawable resource was used as the background.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <size android:width="@dimen/card_avatar_border_width"
        android:height="@dimen/card_avatar_border_width" />
    <stroke android:color="@color/lb_tv_white"
        android:width="4dp" />
</shape>

Use the view hierarchy tool in Android Studio or enable show layout bounds in the developer options to better understand how the padding and margins around each card affects the spacing between them and the border around the image.

What have you customized?

Leanback offers a lot of flexibility for building templated UIs for Android TV. In five short lines of code, we are able to customize the leanback component to support circular imagery! This is one example of how to customize leanback.

What use cases do you have where you needed to customize leanback? Leave a comment or send me a tweet (@benjamintravels) to continue the discussion.

Android
Android Tv
Android App Development
Leanback
Recommended from ReadMedium