Skip to main content
This guide walks you through creating a tab-based messaging UI using Android and CometChat UIKit. The UI uses BottomNavigationView with different sections for Chats, Calls, Users, and Groups, allowing seamless navigation.

User Interface Preview

This layout consists of:
  1. Bottom Navigation Bar – Provides quick access to main sections (Chats, Calls, Users, Groups).
  2. Fragment Container – Displays the selected section’s content using Android Fragments.
  3. Dynamic Content – Each tab loads its respective Fragment with CometChat UI components.

Step-by-Step Guide

This implementation uses Android’s BottomNavigationView pattern:
  1. TabbedActivity hosts the bottom navigation and fragment container
  2. User taps a tab in the bottom navigation
  3. The corresponding Fragment is loaded into the container
  4. Each Fragment displays its CometChat UI component (Conversations, CallLogs, Users, or Groups)
This is the standard Android pattern for apps with multiple top-level destinations.

Step 1: Set Up Tabbed Activity

Create a new Activity called TabbedActivity with BottomNavigationView to manage tab navigation.

Project Structure

Create the following files in your Android project:
src/main/java/your-package-name/
├── TabbedActivity.kt (or .java)
├── ChatsFragment.kt (or .java)
├── CallLogsFragment.kt (or .java)
├── UsersFragment.kt (or .java)
└── GroupsFragment.kt (or .java)

src/main/java/your-package-name/
├── res/
│   ├── layout/
│   │   ├── activity_tabbed.xml
│   │   ├── fragment_chats.xml
│   │   ├── fragment_call_logs.xml
│   │   ├── fragment_users.xml
│   │   └── fragment_groups.xml
│   └── menu/
│       └── bottom_nav_menu.xml

Vector Drawable Icons

Download the navigation icons from the CometChat UI Kit repository: 🔗 GitHub Drawable Resources Place the icon files (ic_chats.xml, ic_calls.xml, ic_user.xml, ic_group.xml) in your res/drawable/ directory.

Implementation

TabbedActivity.kt
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.Fragment

import com.google.android.material.bottomnavigation.BottomNavigationView

class TabbedActivity : AppCompatActivity() {

    private lateinit var bottomNavigationView: BottomNavigationView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_tabbed)

        setupWindowInsets()
        initViews()
        setupNavigation(savedInstanceState)
    }

    private fun setupWindowInsets() {
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
    }

    private fun initViews() {
        bottomNavigationView = findViewById(R.id.bottomNavigationView)
    }

    private fun setupNavigation(savedInstanceState: Bundle?) {
        bottomNavigationView.setOnItemSelectedListener { item ->
            val fragment = createFragmentForNavItem(item.itemId)
            replaceFragment(fragment)
            true
        }

        // Set default fragment only when activity is first created
        if (savedInstanceState == null) {
            replaceFragment(ChatsFragment())
            bottomNavigationView.selectedItemId = R.id.nav_chats
        }
    }

    private fun createFragmentForNavItem(itemId: Int): Fragment {
        return when (itemId) {
            R.id.nav_chats -> ChatsFragment()
            R.id.nav_call_logs -> CallLogsFragment()
            R.id.nav_users -> UsersFragment()
            R.id.nav_groups -> GroupsFragment()
            else -> ChatsFragment()
        }
    }

    private fun replaceFragment(fragment: Fragment) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragmentContainer, fragment)
            .commit()
    }
}
You must use an activity that supports the lifecycle API, such as:
  • AppCompatActivity
  • ComponentActivity
  • FragmentActivity
This is necessary to properly manage the UI Kit’s lifecycle events.

Step 2: Create Fragments for Each Tab

Each tab displays a different CometChat UI component wrapped in a Fragment.

Chats Fragment

ChatsFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class ChatsFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_chats, container, false)
    }
}

Call Logs Fragment

Make sure you’ve added the Calls SDK dependency to enable voice and video calling features.
CallLogsFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class CallLogsFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_call_logs, container, false)
    }
}

Users Fragment

UsersFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class UsersFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_users, container, false)
    }
}

Groups Fragment

GroupsFragment.kt
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup

import androidx.fragment.app.Fragment

class GroupsFragment : Fragment() {

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_groups, container, false)
    }
}

Step 3: Launch TabbedActivity from Your App

Update your MainActivity to launch TabbedActivity after successful login:
MainActivity.kt
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.enableEdgeToEdge
import com.cometchat.chat.core.CometChat
import com.cometchat.chat.exceptions.CometChatException
import com.cometchat.chat.models.User
import com.cometchat.chatuikit.shared.cometchatuikit.CometChatUIKit
import com.cometchat.chatuikit.shared.cometchatuikit.UIKitSettings

class MainActivity : ComponentActivity() {

    private val TAG = "MainActivity"

    private val appID = "APP_ID" // Replace with your App ID
    private val region = "REGION" // Replace with your App Region
    private val authKey = "AUTH_KEY" // Replace with your Auth Key or leave blank if you are authenticating using Auth Token

    private val uiKitSettings = UIKitSettings.UIKitSettingsBuilder()
        .setRegion(region)
        .setAppId(appID)
        .setAuthKey(authKey)
        .subscribePresenceForAllUsers()
        .build()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        CometChatUIKit.init(this, uiKitSettings, object : CometChat.CallbackListener<String?>() {
            override fun onSuccess(successString: String?) {

                Log.d(TAG, "Initialization completed successfully")

                loginUser()
            }

            override fun onError(e: CometChatException?) {}
        })
    }

    private fun loginUser() {
        CometChatUIKit.login("cometchat-uid-1", object : CometChat.CallbackListener<User>() {
            override fun onSuccess(user: User) {
 
                // Launch Tab-Based Chat Experience (Chats, Calls, Users, Groups)
                startActivity(Intent(this@MainActivity, TabbedActivity::class.java))
            }

            override fun onError(e: CometChatException) {
                // Handle login failure (e.g. show error message or retry)
                Log.e("Login", "Login failed: ${e.message}")
            }
        })
    }
}

Running the Application

Once you’ve completed the setup, build and run your Android application:
gradle build
Required PermissionsEnsure you’ve added the necessary permissions in your AndroidManifest.xmland initialized CometChat in your Application class:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
For Call Features, also add:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Next Steps

Enhance the User Experience