Channel List View

LAST EDIT Apr 08 2021

ChannelListView is responsible for displaying list of channels. It also supports loading and empty states. By default, a single list item shows the channel name, user's read state, last message, and the time of the last message. It also implements swiping behaviour which allows handling different actions on the channel: 

You can use the view in your layout as shown below:

1
2
3
4
<io.getstream.chat.android.ui.channel.list.ChannelListView 
    android:id="@+id/channelsView" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" />

Binding with a ViewModel

Copied!

ChannelListView allows you to display different channels list states and handle common user's interactions, but it doesn't contain logic for getting channels from the Stream API. The Android SDK comes with ChannelListViewModel which contains default logic for this view, which can be easily bound to it using bindView:

1
2
3
4
5
6
7
8
9
10
11
12
val viewModel: ChannelListViewModel by viewModels { 
    ChannelListViewModelFactory( 
        filter = Filters.and( 
            Filters.eq("type", "messaging"), 
            Filters.`in`("members", listOf(ChatDomain.instance().currentUser.id)), 
        ), 
        sort = ChannelListViewModel.DEFAULT_SORT, 
        limit = 30, 
    ) 
} 
// Bind it with ChannelListView 
viewModel.bindView(channelListView, viewLifecycleOwner)
1
2
3
4
5
6
7
8
9
10
11
12
13
// Get ViewModel 
FilterObject filter = Filters.and( 
    Filters.eq("type", "messaging"), 
    Filters.in("members", singletonList(ChatDomain.instance().getCurrentUser().getId())) 
); 
int limit = 30; 
 
ChannelListViewModelFactory factory = new ChannelListViewModelFactory(filter, ChannelListViewModel.DEFAULT_SORT, limit); 
ChannelListViewModel viewModel = new ViewModelProvider(this, factory) 
    .get(ChannelListViewModel.class); 
                     
// Bind it with ChannelListView 
ChannelListViewModelBinding.bind(viewModel, channelListView, getViewLifecycleOwner());

This call connects the ViewModel with the view and from that point, different channels view states, as well as channel's pagination, will be handled automatically.

It's worth mentioning that you don't need to query channels by yourself. The first call will be done during the creation of ChannelListViewModel and the list will be kept updated automatically based on received events.

Handling Channel Actions

Copied!

ChannelListView comes with a set of channel actions out of the box. You can:

  • See channel members

  • Delete the channel if you have sufficient permissions

  • Leave the channel if it's a group channel

There are some actions (e.g. clicking on member or Viewing Info) that require additional handling:

1
2
3
4
5
6
7
channelListView.setChannelInfoClickListener { channel -> 
    // Handle Channel Info Click 
} 
 
channelListView.setUserClickListener { user -> 
    // Handle Member Click 
}
1
2
3
4
5
6
7
channelListView.setChannelInfoClickListener((channel) -> { 
    // Handle Channel Info Click 
}); 
 
channelListView.setUserClickListener((user) -> { 
    // Handle Member Click 
});

Handling User Interactions

Copied!

ChannelListView exposes multiple methods for setting listeners for user interactions handling, that includes different user clicks handling:

1
2
3
4
5
6
7
8
channelListView.setChannelItemClickListener { channel -> 
    // Handle Channel Click 
} 
 
channelListView.setChannelLongClickListener { channel -> 
    // Handle Channel Click 
    true 
}
1
2
3
4
5
6
7
8
channelListView.setChannelItemClickListener((channel) -> { 
    // Handle Channel Click 
}); 
 
channelListView.setChannelLongClickListener((channel) -> { 
    // Handle Channel Long Click 
    return true; 
});

A full list of available listeners to set can be found here.

Customizing Default Views

Copied!

The view allows setting custom loading and empty views, as well as and separators via code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Create loading view and layout params 
val loadingView = ProgressBar(context) 
val layoutParams = FrameLayout.LayoutParams( 
    FrameLayout.LayoutParams.WRAP_CONTENT, 
    FrameLayout.LayoutParams.WRAP_CONTENT, 
    Gravity.CENTER 
) 
channelListView.setEmptyStateView(loadingView, layoutParams) 
 
// Create empty state view and use default layout params 
val emptyStateView = TextView(context).apply { 
    text = "No channels available" 
} 
channelListView.setEmptyStateView(emptyStateView) 
 
// Set custom item separator drawable 
channelListView.setItemSeparator(R.drawable.stream_ui_divider) 
 
// Add separator to the last item 
channelListView.setShouldDrawItemSeparatorOnLastItem(true)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Create loading view and layout params 
ProgressBar loadingView = new ProgressBar(getContext()); 
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( 
        FrameLayout.LayoutParams.WRAP_CONTENT, 
        FrameLayout.LayoutParams.WRAP_CONTENT, 
        Gravity.CENTER 
); 
channelListView.setEmptyStateView(loadingView, layoutParams); 
 
// Create empty state view and use default layout params 
TextView emptyStateView = new TextView(getContext()); 
emptyStateView.setText("No channels available"); 
channelsView.setEmptyStateView(emptyStateView); 
 
// Set custom item separator drawable 
channelListView.setItemSeparator(R.drawable.stream_ui_divider); 
 
// Add separator to the last item 
channelListView.setShouldDrawItemSeparatorOnLastItem(true);

Custom ViewHolder Factory

Copied!

ChannelListView provides a mechanism for completely changing the default view holders, as well as introducing different types of views. All you need to do is to provide your own ChannelListItemViewHolderFactory implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class CustomChannelListItemViewHolderFactory : ChannelListItemViewHolderFactory() { 
    override fun getItemViewType(item: ChannelListItem): Int { 
        // Override together with createViewHolder() to introduce different view holder types 
        return super.getItemViewType(item) 
    } 
 
    override fun createViewHolder(parentView: ViewGroup, viewType: Int): BaseChannelListItemViewHolder { 
        // Override to create custom create view holder logic 
        return super.createViewHolder(parentView, viewType) 
    } 
 
    override fun createChannelViewHolder(parentView: ViewGroup): BaseChannelListItemViewHolder { 
        // Create custom channel view holder 
        return super.createChannelViewHolder(parentView) 
    } 
 
    override fun createLoadingMoreViewHolder(parentView: ViewGroup): BaseChannelListItemViewHolder { 
        // Create custom loading more view holder 
        return super.createLoadingMoreViewHolder(parentView) 
    } 
} 
 
// Create custom view holder factory 
val customFactory = CustomChannelListItemViewHolderFactory() 
 
// Set custom view holder factory 
channelListView.setViewHolderFactory(customFactory)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class CustomChannelListItemViewHolderFactory extends ChannelListItemViewHolderFactory { 
    @Override 
    public int getItemViewType(@NotNull ChannelListItem item) { 
        // Override together with createViewHolder() to introduce different view holder types 
        return super.getItemViewType(item); 
     } 
 
     @NotNull 
     @Override 
    public BaseChannelListItemViewHolder createViewHolder(@NotNull ViewGroup parentView, int viewType) { 
        // Override to create custom create view holder logic 
        return super.createViewHolder(parentView, viewType); 
    } 
 
    @NotNull 
    @Override 
    protected BaseChannelListItemViewHolder createChannelViewHolder(@NotNull ViewGroup parentView) { 
        // Create custom channel view holder 
        return super.createChannelViewHolder(parentView); 
    } 
 
    @NotNull 
    @Override 
    protected BaseChannelListItemViewHolder createLoadingMoreViewHolder(@NotNull ViewGroup parentView) { 
        // Create custom loading more view holder 
        return super.createLoadingMoreViewHolder(parentView); 
    } 
} 
 
// Create custom view holder factory 
CustomChannelListItemViewHolderFactory customFactory = new CustomChannelListItemViewHolderFactory(); 
 
// Set custom view holder factory 
channelListView.setViewHolderFactory(customFactory);

NOTE: The View Holder Factory needs to be set before ChannelListView initializes its adapter.

Other Customizations

Copied!

The view is configurable either by attributes (a list of available attributes can be found here) and can be configured programmatically using TransformStyle.channelListStyleTransformer (a list of supported customizations can be found here):

1
2
3
4
TransformStyle.channelListStyleTransformer = StyleTransformer { defaultViewStyle -> 
    // Modify default view style 
    defaultViewStyle.copy(optionsEnabled = false) 
}
1
2
3
4
5
TransformStyle.INSTANCE.setChannelListStyleTransformer(viewStyle -> { 
            // Modify default view style 
            return viewStyle; 
       } 
);

NOTE: The style transformer should be set before the view is rendered to make sure that the new style was applied.