This topic is on Kotlin Change Tab Icon/Text/Background Color/Text Color.
We will change the icon , color ,text color, background color etc. of the android tab when it is selected by the user.
This feature is mainly used for indicating the current selected tab. Developers change the text and icon color of selected tab so that it can be differentiated from other deselected tabs easily.
First of all, watch the below youtube content.
Step 1. Adding Colors
Go to app->res->values directory and open the colors.xml file. Add the following lines in it
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#525e5e</color> <color name="colorPrimaryDark">#41f8f8</color> <color name="colorAccent">#525e5e</color> <color name="greyback">#1e2926</color> <color name="black">#000000</color> <color name="view">#5e6664</color> <color name="tranparent">#00ffffff</color> <color name="white">#FFFFFF</color> </resources>
Step 2. Some Strings
Now in the same directory of app->res->values open a file called strings.xml
strings.xml file should have the below code lines
<resources> <string name="app_name">ChangeTabKotlin</string> <string name="login">Login</string> <string name="intro">Introduction</string> <string name="Product">Product</string> <string name="Location">Location</string> <!-- TODO: Remove or change this placeholder text --> <string name="hello_blank_fragment">Hello blank fragment</string> </resources>
Step 3. Some Icons
We want to change the icon of the selected tab. For this, we need to add different icons for both the states of the tab : selected and deselected
And these two types of icons are different for different tabs.
Click on the following to download various icons.
Now you need to copy all these icon images into the app->res->mipmap folder.
Step 4. Necessary Fragments
We will create fragment for each tab. This example has four tabs so we will have to create four new fragments.
So go on and make a new fragment called IntroFragment
In your fragment_intro.xml file, add the following
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".IntroFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="50sp" android:text="@string/intro" /> </FrameLayout>
Below is the code for IntroFragment.kt file.
import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class IntroFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_intro, container, false) } }
Second fragment is LocationFragment
Code for fragment_location.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".LocationFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="50sp" android:text="Location" /> </FrameLayout>
Following is for LocationFragment.kt
import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class LocationFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_location, container, false) } }
Then next fragment is Login Fragment
Following is as fragment_login.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".LoginFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="50sp" android:text="@string/login" /> </FrameLayout>
And about LoginFragment.kt
import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class LoginFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_login, container, false) } }
Next one is Product fragment which is the last.
Below is code for fragment_product.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ProductFragment"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="50sp" android:text="@string/Product" /> </FrameLayout>
Copy the following into ProductFragment.kt
import android.os.Bundle import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup class ProductFragment : Fragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_product, container, false) } }
Step 5. Last in on Main Files
Now we are left with main files only.
Write down the below source lines in activity_main.xml file.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="50dp" android:orientation="horizontal" android:background="@mipmap/tab_bar_bg" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" android:layout_marginRight="5dp" android:layout_marginLeft="5dp"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:id="@+id/llIntro"> <ImageView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layout_marginTop="5dp" android:paddingTop="5dp" android:id="@+id/ivIntro" android:src="@mipmap/icon_intro_normal" android:foregroundGravity="center" /> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/intro" android:id="@+id/tvIntro" android:layout_weight="1" android:textSize="12sp" android:gravity="center" /> </LinearLayout> <View android:layout_width="0.5dp" android:layout_height="match_parent" android:background="@color/view" /> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:id="@+id/llProduct" > <ImageView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layout_marginTop="5dp" android:paddingTop="5dp" android:foregroundGravity="center" android:id="@+id/ivProduct" android:src="@mipmap/icon_product" /> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/Product" android:id="@+id/tvProduct" android:layout_weight="1" android:gravity="center" android:textSize="12sp" /> </LinearLayout> <View android:layout_width="0.5dp" android:layout_height="match_parent" android:background="@color/view" /> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:id="@+id/llLocation" > <ImageView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layout_marginTop="5dp" android:paddingTop="5dp" android:id="@+id/ivLocation" android:src="@mipmap/icon_location" /> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/Location" android:id="@+id/tvLocation" android:layout_weight="1" android:gravity="center" android:textSize="12sp" /> </LinearLayout> <View android:layout_width="0.5dp" android:layout_height="match_parent" android:background="@color/view" /> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:id="@+id/llLogin" > <ImageView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:layout_marginTop="5dp" android:paddingTop="5dp" android:id="@+id/ivLogin" android:src="@mipmap/icon_login2" /> <TextView android:layout_width="match_parent" android:layout_height="0dp" android:text="@string/login" android:id="@+id/tvLogin" android:layout_weight="1" android:gravity="center" android:textSize="12sp" /> </LinearLayout> </LinearLayout> <FrameLayout android:id="@+id/container_body" android:layout_width="match_parent" android:layout_height="match_parent"> </FrameLayout> </LinearLayout>
This file is creating the layout of our tabs. We will set all the icons on this file.
By default, we will set the icons for deselected files. Logic for presenting and changing icons will be written in the Main Kotlin file.
Now write the below source code lines in MainActivity.kt file.
import android.support.v4.app.Fragment import android.support.v4.app.FragmentManager import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView class MainActivity : AppCompatActivity() { private var currentSelected = 0 private val intro = "intro" private val product = "product" private val location = "location" private val login = "login" private var ivIntro: ImageView? = null private var ivProduct: ImageView? = null private var ivLocation: ImageView? = null private var ivLogin: ImageView? = null private var tvIntro: TextView? = null private var tvProduct: TextView? = null private var tvLocation: TextView? = null private var tvLogin: TextView? = null private var llIntro: LinearLayout? = null private var llProduct: LinearLayout? = null private var llLocation: LinearLayout? = null private var llLogin: LinearLayout? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) llIntro = findViewById(R.id.llIntro) as LinearLayout llProduct = findViewById(R.id.llProduct) as LinearLayout llLocation = findViewById(R.id.llLocation) as LinearLayout llLogin = findViewById(R.id.llLogin) as LinearLayout ivIntro = findViewById(R.id.ivIntro) as ImageView ivProduct = findViewById(R.id.ivProduct) as ImageView ivLocation = findViewById(R.id.ivLocation) as ImageView ivLogin = findViewById(R.id.ivLogin) as ImageView tvIntro = findViewById(R.id.tvIntro) as TextView tvProduct = findViewById(R.id.tvProduct) as TextView tvLocation = findViewById(R.id.tvLocation) as TextView tvLogin = findViewById(R.id.tvLogin) as TextView llIntro!!.setOnClickListener { if (currentSelected == 1) { } else { supportActionBar!!.title = "Introduction" ivIntro!!.setImageResource(R.mipmap.icon_intro_selected) tvIntro!!.setTextColor(resources.getColor(R.color.white)) llIntro!!.setBackgroundDrawable(resources.getDrawable(R.drawable.roundleft)) unselectElse(1) removeAllFragment(IntroFragment(), false, intro) } } llProduct!!.setOnClickListener { if (currentSelected == 2) { } else { supportActionBar!!.title = "Product" ivProduct!!.setImageResource(R.mipmap.icon_product_selected) tvProduct!!.setTextColor(resources.getColor(R.color.white)) llProduct!!.setBackgroundColor(resources.getColor(R.color.colorPrimary)) unselectElse(2) removeAllFragment(ProductFragment(), false, product) } } llLocation!!.setOnClickListener { if (currentSelected == 3) { } else { supportActionBar!!.title = "Location" ivLocation!!.setImageResource(R.mipmap.icon_location_selected) tvLocation!!.setTextColor(resources.getColor(R.color.white)) llLocation!!.setBackgroundColor(resources.getColor(R.color.colorPrimary)) unselectElse(3) removeAllFragment(LocationFragment(), false, location) } } llLogin!!.setOnClickListener { if (currentSelected == 4) { } else { supportActionBar!!.title = "Login" ivLogin!!.setImageResource(R.mipmap.icon_login_selected) tvLogin!!.setTextColor(resources.getColor(R.color.white)) llLogin!!.setBackgroundDrawable(resources.getDrawable(R.drawable.roundback)) unselectElse(4) removeAllFragment(LoginFragment(), false, login) } } } private fun unselectElse(current: Int) { when (currentSelected) { 1 -> { ivIntro!!.setImageResource(R.mipmap.icon_intro_normal) tvIntro!!.setTextColor(resources.getColor(R.color.colorPrimary)) llIntro!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } 2 -> { ivProduct!!.setImageResource(R.mipmap.icon_product) tvProduct!!.setTextColor(resources.getColor(R.color.colorPrimary)) llProduct!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } 3 -> { ivLocation!!.setImageResource(R.mipmap.icon_location) tvLocation!!.setTextColor(resources.getColor(R.color.colorPrimary)) llLocation!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } 4 -> { ivLogin!!.setImageResource(R.mipmap.icon_login2) tvLogin!!.setTextColor(resources.getColor(R.color.colorPrimary)) llLogin!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } } if (currentSelected == 0) { currentSelected = current } } fun removeAllFragment(replaceFragment: Fragment, addToBackStack: Boolean, tag: String) { val manager = supportFragmentManager val ft = manager.beginTransaction() manager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) if (addToBackStack) { ft.addToBackStack(tag) } ft.replace(R.id.container_body, replaceFragment) ft.commitAllowingStateLoss() } }
Deep Information
Compiler will first define some image views, text views and linear layouts.
Linear layout represent the background of whole one tab. We have four different linear layouts for four various tabs.
First of all, see the following
llIntro!!.setOnClickListener { if (currentSelected == 1) { } else { supportActionBar!!.title = "Introduction" ivIntro!!.setImageResource(R.mipmap.icon_intro_selected) tvIntro!!.setTextColor(resources.getColor(R.color.white)) llIntro!!.setBackgroundDrawable(resources.getDrawable(R.drawable.roundleft)) unselectElse(1) removeAllFragment(IntroFragment(), false, intro) } }
When the user clicks the intro tab, compiler will run the above code.
It will first check, if the value of the variable currentSelected is 1 or not. If it is 1 then it means that Intro tag is already selected and we do not need to do anything.
If it is not 1 then compiler will go into the else statement. Here, compiler will change the value of the supportActionBar.
Then it will change the image of the tab using setImageResource() method.
After this, it will use setTextColor() method to change the color of the tab text.
Then compiler will change the background of the tab using setBackgroundDrawable() method.
Below is the code for unselectElse() method.
private fun unselectElse(current: Int) { when (currentSelected) { 1 -> { ivIntro!!.setImageResource(R.mipmap.icon_intro_normal) tvIntro!!.setTextColor(resources.getColor(R.color.colorPrimary)) llIntro!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } 2 -> { ivProduct!!.setImageResource(R.mipmap.icon_product) tvProduct!!.setTextColor(resources.getColor(R.color.colorPrimary)) llProduct!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } 3 -> { ivLocation!!.setImageResource(R.mipmap.icon_location) tvLocation!!.setTextColor(resources.getColor(R.color.colorPrimary)) llLocation!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } 4 -> { ivLogin!!.setImageResource(R.mipmap.icon_login2) tvLogin!!.setTextColor(resources.getColor(R.color.colorPrimary)) llLogin!!.setBackgroundColor(resources.getColor(R.color.tranparent)) currentSelected = current } } if (currentSelected == 0) { currentSelected = current } }
This method will get the number of current selected tab. Here, it will use when() method. This method have four different conditions.
When first tab (introduction) is selected, value for when() method will be 1.
Thus, compiler will execute the lines associated with option 1 in the when() method.
Following are the code lines for removeAllFragment() method.
fun removeAllFragment(replaceFragment: Fragment, addToBackStack: Boolean, tag: String) { val manager = supportFragmentManager val ft = manager.beginTransaction() manager.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE) if (addToBackStack) { ft.addToBackStack(tag) } ft.replace(R.id.container_body, replaceFragment) ft.commitAllowingStateLoss() }
This method will first remove all the current opened fragments. Then it will simply open the new fragment which user have selected. For example, if user have selected last tab (login) then this method will first empty the fragment back stack and then it will open the Login Fragment in container_body
Download For Kotlin Change Tab
https://github.com/demonuts/Kotlin-Change-Tab-Icon-Text-Background-Color-Text-Color-When-Selected