Different colors for selected tab in BottomNavigationView in Android Kotlin(Programmatically)

Many times we need to use different colors for the selected tab in BottomNavigationView, displayed in the picture below.

Different colors for selected tab in BottomNavigationView in Android
Different colors for selected tab in BottomNavigationView in Android

Currently you can set only on color for selected tab from xml layout like this, using these 2 properties: app:itemIconTint and app:itemTextColor

<com.google.android.material.bottomnavigation.BottomNavigationView
  android:id="@+id/bnv"
  android:layout_width="0dp"
  android:layout_height="wrap_content"
  android:background="@android:color/white"
  app:itemIconTint="@color/color_bnv1"
  app:itemTextColor="@color/color_bnv1"
  app:labelVisibilityMode="labeled"
  app:layout_constraintBottom_toBottomOf="parent"
  app:layout_constraintEnd_toEndOf="parent"
  app:layout_constraintStart_toStartOf="parent"
  app:menu="@menu/menu_bottom_navigation_view" />

Here you can see we use @color/color_bnv1 for both property which is a color state selector from res/color directory. Here is the implementation for that.

<!-- res/color/color_bnv1.xml -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="@color/colorTab1" android:state_checked="true" />
  <!-- @color/colorTab1 = #006064 //define this in your res/values/color.xml or change the color directly here -->
  <item android:color="@android:color/darker_gray" android:state_checked="false" />
</selector>

Now for the above code, you see the result like this,

BottomNavigationView in Android
BottomNavigationView in Android

Now we need to apply different app:itemIconTint and app:itemTextColor when each tab is selected. So we apply both of these properties to the BottomNavigationView programmatically at runtime in our activity file in Kotlin.

For that we need use setOnNavigationItemSelectedListener from BottomNavigationView, which will give us the event when any tab is selected by user.

bnv.setOnNavigationItemSelectedListener {
  when (it.itemId) {
    R.id.action_tab1 -> {
      
    }
    R.id.action_tab2 -> {
      
    }
    R.id.action_tab3 -> {
      
    }
  }
  true
}

We will use the same file @color/color_bnv1 here. But here, we need to create 3 such different files for the colors we need. So we will create @color/color_bnv2 and @color/color_bnv3 in res/color, which should looks like this.

<!-- res/color/color_bnv2.xml -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="@color/colorTab2" android:state_checked="true" />
  <!-- @color/colorTab2 = #BF360C //define this in your res/values/color.xml or change the color directly here -->
  <item android:color="@android:color/darker_gray" android:state_checked="false" />
</selector>
<!-- res/color/color_bnv3.xml -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:color="@color/colorTab3" android:state_checked="true" />
  <!-- @color/colorTab3 = #4A148C //define this in your res/values/color.xml or change the color directly here -->
  <item android:color="@android:color/darker_gray" android:state_checked="false" />
</selector>

Now here we will set both properties using its Kotlin syntax which is itemIconTintList and itemTextColor for BottomNavigationView. We use the same @color/color_bnv1, @color/color_bnv2 and @color/color_bnv3 for each of the tab selected.

bnv.setOnNavigationItemSelectedListener {
  when (it.itemId) {
    R.id.action_tab1 -> {
      tv.text = getString(R.string.str_bnv_tab1) //"Tab 1"
      tv.setTextColor(ContextCompat.getColor(this, R.color.colorTab1))
      bnv.itemIconTintList = ContextCompat.getColorStateList(this, R.color.color_bnv1)
      bnv.itemTextColor = ContextCompat.getColorStateList(this, R.color.color_bnv1)
    }
    R.id.action_tab2 -> {
      tv.text = getString(R.string.str_bnv_tab2) //"Tab 2"
      tv.setTextColor(ContextCompat.getColor(this, R.color.colorTab2))
      bnv.itemIconTintList = ContextCompat.getColorStateList(this, R.color.color_bnv2)
      bnv.itemTextColor = ContextCompat.getColorStateList(this, R.color.color_bnv2)
    }
    R.id.action_tab3 -> {
      tv.text = getString(R.string.str_bnv_tab3) //"Tab 3"
      tv.setTextColor(ContextCompat.getColor(this, R.color.colorTab3))
      bnv.itemIconTintList = ContextCompat.getColorStateList(this, R.color.color_bnv3)
      bnv.itemTextColor = ContextCompat.getColorStateList(this, R.color.color_bnv3)
    }
  }
  true
}

When the user opens the app for the first time, you can use the following code that will preselect the desired tab and will execute the listener for that.

bnv.selectedItemId = R.id.action_tab1

You can find the whole code in my github repo: https://github.com/dakshbhatt21/a-computer-engineer

Create PDF and save to the sdcard in Android

Create PDF file and save it to sdcard in Android
Create PDF file and save it to sdcard in Android

In this article, we will create PDF file of the current view and then save it to the sdcard(internal storage) as pdf file. Here we use PdfDocument (https://developer.android.com/reference/android/graphics/pdf/PdfDocument) which added from API 19(Android KitKat). So you can use it above KitKat version of Android.

First of all we will create Bitmap of the view which we want to save on the PDF file. So for that we need to get the heigh and width of the view, so here we do all the operation in the ‘onWindowFocusChanged’ method instead of ‘onCreate’ method. So the basic structure of the file will look like this.

private RelativeLayout rlContainer;

private int width, height;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_pdf);

  rlContainer = findViewById(R.id.rl_container);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);

  width = rlContainer.getWidth();
  height = rlContainer.getHeight();
}

Here we have on RelativeLayout which contains all the elements we need to print on the PDF file. So we will initialise it in onCreate and then get its width and height in onWindowFocusChanged. If you try to get the width and height in onCreate, it will be 0 because at that time the view did not rendered on the screen. So we will use the above method for that.

Now we will create a Bitmap of that relative layout using following code. Later we will draw this Bitmap on PDF file using Canvas of the PDF file.

Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c1 = new Canvas(b);
rlContainer.draw(c1);

Now we initialise PdfDocument and create pages in that PDF file. For that we use PdfDocument.Page class. If we have 5 pages in our PDF file then we have to create 5 object of PdfDocument.Page and add them to PdfDocument. Then we fetch the canvas of the PDF page and draw our Bitmap on it. Please check the code below.

PdfDocument pd = new PdfDocument();

PdfDocument.PageInfo pi = new PdfDocument.PageInfo.Builder(width, height, 1).create();
PdfDocument.Page p = pd.startPage(pi);
Canvas c = p.getCanvas();
c.drawBitmap(b, 0, 0, new Paint());
pd.finishPage(p);

pd.close();

Here we can iterate the code from line 3 to line 7 to add more pages to the PDF files. After that we need to close the PdfDocument. This will draw our bitmap to the PDF file. Now to write this PdfDocument to the file on sdcard(internal storage), we need to create a File and write PdfDocument to its OutputStream. But make sure that you write this code before closing the PdfDocument pd.close(). Here is the code for that.

try {
  //make sure you have asked for storage permission before this
  File f = new File(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer-pdf-test.pdf");
  pd.writeTo(new FileOutputStream(f));
} catch (FileNotFoundException fnfe) {
  fnfe.printStackTrace();
} catch (IOException ioe) {
  ioe.printStackTrace();
}

pd.close();

Please make sure that before running above code, you have the storage permission granted by user otherwise you will get error. Please check for the runtime Android permission for that. Now your PDF file is saved at your provided location on your sdcard(internal storage).

Here is the full code.

private RelativeLayout rlContainer;

private int width, height;

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_pdf);

  rlContainer = findViewById(R.id.rl_container);
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
  super.onWindowFocusChanged(hasFocus);

  width = rlContainer.getWidth();
  height = rlContainer.getHeight();

  Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  Canvas c1 = new Canvas(b);
  rlContainer.draw(c1);

  PdfDocument pd = new PdfDocument();

  PdfDocument.PageInfo pi = new PdfDocument.PageInfo.Builder(width, height, 1).create();
  PdfDocument.Page p = pd.startPage(pi);
  Canvas c = p.getCanvas();
  c.drawBitmap(b, 0, 0, new Paint());
  pd.finishPage(p);

  try {
    //make sure you have asked for storage permission before this
    File f = new File(Environment.getExternalStorageDirectory() + File.separator + "a-computer-engineer-pdf-test.pdf");
    pd.writeTo(new FileOutputStream(f));
  } catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
  } catch (IOException ioe) {
    ioe.printStackTrace();
  }

  pd.close();
}

If you find any problem or doubt, please mention in comments. Do not forget to share!

Download Source Code: https://github.com/dakshbhatt21/a-computer-engineer