4 min read

Related Tag List

Related Tag List

RelatedTagListView is a component that displays a list of related tags to a user. For users with a slower connection or queries that don't have any related tags, RelatedTagListView also supports loading and empty states.

Light Mode Dark Mode
related tag list view light mode related tag list view dark mode

By default, a single list item shows the following:

  • Tag name
  • Left icon: usually used as type icon (curated, etc...)
  • Right icon: usually used as status icon

Usage

To use RelatedTagListView, include it in your XML layout as shown below:

<co.empathy.x.components.ui.relatedtag.list.RelatedTagListView
    android:id="@+id/relatedTagListView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

We recommend using the RelatedTagListViewModel to get the full list of data from the API and then render it using the RelatedTagListView.

The basic setup of the ViewModel and connecting it to the View is done the following way:

// Instantiate the ViewModel
val viewModel: RelatedTagListViewModel by viewModels {
    RelatedTagListViewModelFactory()
}
// Bind the ViewModel with RelatedTagListView
viewModel.bindView(relatedTagListView, viewLifecycleOwner)

To instantiate RelatedTagListViewModel you may want to pass an instance of the RelatedTagsRepository interface. See this point to read more.

All the logic of subscribing to data emitted by the ViewModel is provided by the bindView function. Other than related tags data loading, the ViewModel is also handling actions like user clicking a related tag by default.

And that would be actions necessary to use RelatedTagListView. To get deeper and understand how to customize it, please keep reading.

Handling Actions

RelatedTagListView includes a set of related tags actions. Actions on RelatedTagListView items are available on click. With these, you can:

  • Select the related tag
  • Deselect the related tag
Light Mode Dark Mode
related tag list view selected light mode related tag list view selected dark mode

The following actions are implemented by default, but you can add your own listeners if you want to extend the behaviour:

relatedTagListView.setRelatedTagItemClickListener { relatedTag ->
    // Handle related tag click
}
relatedTagListView.setRelatedTagListOnItemsChangeListener {
    // Handle on related tag list items change
}

Style Customization

There are two ways to customize the appearance of RelatedTagListView:

  • Using XML attributes
  • Using the StyleCustomizer API at runtime to customize the style of all RelatedTagListView instances

Using XML Attributes

There are many XML attributes that can be used to customize the appearance of the related tag list. The most useful ones include:

  • xIsRelatedTagLeftIconVisible: Whether the left icon should be displayed.
  • xIsRelatedTagRightIconVisible: Whether the right icon should be displayed.
  • xRelatedTagLeftIcon: Drawable reference for the related tag left icon.
  • xRelatedTagRightIcon: Drawable reference for the related tag right icon.
  • xRelatedTagTitleTextColor: Color of the related tag title text.
  • xRelatedTagTitleTextSize: Size of the related tag title text.
  • xRelatedTagBackgroundColor: Background color of the related tag list item.

The full list of available XML attributes is available under RelatedTagListView styleable, here (opens new window).

Using StyleCustomizer API

The following example shows how to modify the style of all RelatedTagListView instances globally to:

  • Change the background color
  • Change the title text style
  • Change the default icons

To make these changes, we need to define a custom XComponents.relatedTagListViewStyleCustomizer:

XComponents.relatedTagListViewStyleCustomizer = StyleCustomizer { defaultViewStyle ->
    defaultViewStyle.copy(
        relatedTagBackgroundColor = ColorStateList.valueOf(Color.BLUE),
        relatedTagRightIcon = context.getDrawable(R.drawable.x_ic_curated)!!,
        relatedTagTitleTextStyle = TextStyle(
            color = Color.WHITE,
            size = resources.getDimensionPixelSize(R.dimen.x_font_size_base_xl),
        ),
    )
}

These changes should have the following results:

Before After
before after

note

The StyleCustomizer should be set before the View is rendered to make sure that the new style was applied.

Functional Customization: Creating a Custom ViewHolder Factory

RelatedTagListView provides a way to completely change the default ViewHolders and add different types of views. All you need to do is to provide your own RelatedTagListItemViewHolderFactory. Let's see an example that only displays the tag name, without any icon or border.

  1. Create the custom_related_tag_list_item.xml layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:ellipsize="end"
        android:singleLine="true"
        android:textAllCaps="true"
        android:textColor="#7A7A7A"
        android:textSize="14sp"
        android:textStyle="normal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
    />
</androidx.constraintlayout.widget.ConstraintLayout>
  1. Create a custom ViewHolder and ViewHolder factory:
class CustomRelatedTagListItemViewHolderFactory : RelatedTagListItemViewHolderFactory() {
    override fun createRelatedTagViewHolder(parentView: ViewGroup): BaseRelatedTagListItemViewHolder {
        return CustomRelatedTagViewHolder(parentView, listenerContainer.relatedTagClickListener)
    }
}
class CustomRelatedTagViewHolder(
    parent: ViewGroup,
    private val relatedTagClickListener: RelatedTagListView.RelatedTagClickListener,
    private val binding: CustomRelatedTagListItemBinding = CustomRelatedTagListItemBinding.inflate(
        LayoutInflater.from(parent.context),
        parent,
        false
    ),
) : BaseRelatedTagListItemViewHolder(binding.root) {
    private lateinit var relatedTag: RelatedTag
    init {
        binding.root.setOnClickListener { relatedTagClickListener.onClick(relatedTag) }
    }
    override fun bind(relatedTag: RelatedTag, diff: RelatedTagListPayloadDiff) {
        this.relatedTag = relatedTag
        binding.apply {
            nameTextView.text = relatedTag.tag
        }
    }
}
  1. Set the custom ViewHolder factory on the RelatedTagListView:
relatedTagListView.setViewHolderFactory(CustomRelatedTagListItemViewHolderFactory())

These changes should have the following results:

Related Tag List View Custom ViewHolder

RelatedTagsRepository

When RelatedTagListViewModel is instantiated it needs a RelatedTagsRepository to get the list of related tags. If you don't provide one the ViewModel will use the one set in XAdapter, which is the common one for all RelatedTagListView instances. But sometimes you may want an instance of RelatedTagListView showing tags from another endpoint or with another configuration. In that case, you should provide a custom RelatedTagsRepository implementation, which has the following interface:

public fun interface RelatedTagsRepository : XRepository {
    public suspend fun getRelatedTags(
        query: String,
        selectedRelatedTags: List<RelatedTagDto>,
        requestId: Any
    ): ResponseResult<Failure, List<RelatedTagDto>>
}

You can also use DefaultRelatedTagsRepository - a more detailed implementation that covers the most generic cases and uses the Empathy Platform APIs.

To use your custom RelatedTagsRepository pass it to the RelatedTagListViewModel when you instantiate the ViewModel:

val viewModel: RelatedTagListViewModel by viewModels {
    RelatedTagListViewModelFactory(
        repository = CustomRelatedTagsRepository()
    )
}