In the situations where the background color gets changed, the foreground color should also change to some other color. Otherwise the foreground item may not be properly visible on the background.
In Phimpme Android, we came across this situation when dealing with the bottom navigation bar. We have a preference option in our application which enables the user to change the primary color of the application. This change affects the background color of the bottom navigation bar also. We initially had white as selected foreground item’s color and grey as the unselected items’ color. It was fine for darker background colors. But problem arose when we changed the primary color of the application to the lighter shade of any color. The foreground item which was in white color was not clearly visible over the background. So we had to dynamically decide the foreground color when the background color gets changed.
Deciding the foreground color of the bottom navigation bar in Phimpme Android was tough. The foreground item should not only be visible on the background color but it should also be visibly attractive. We needed a minimal look. So we decided to use only two colors – black and white for the selected item’s color. The unselected items’ color can be fixed. A shade of gray with less alpha can be used for it.
The black and white colors are decided based on the lightness of the background color. We used the rgb value of the background color to find the lightness. We fixed a threshold for this lightness by visual judgement and selected the foreground color from the black and white colors based on this threshold lightness. If the lightness of the background color of the bottom navigation color of Phimpme Android application is less than the defined threshold value, we used white as the foreground color and vice-versa.
The lightness can be found out by taking the average of the red, green and blue values of the background color. We considered 100 as the threshold lightness for deciding the foreground color.
void setIconColor(int color){
if(Color.red(color) + Color.green(color)+ Color.blue(color) < 300)
colors[0] = Color.WHITE;
else
colors[0] = Color.BLACK;
}
For setting the different colors for different states of the foreground items on the bottom navigation bar, we used the setItemIconTintList method which takes ColorStatesList as an argument.
colors[1] = ContextCompat.getColor(this, R.color.bottom_navigation_tabs);
ColorStateList bottomNavList = new ColorStateList(states, colors);
navigationView.setItemIconTintList(bottomNavList);
This above ColorStateList takes a two dimensional array of states for which we wanted to change the color of item and an array of corresponding colors for those states as arguments. In Phimpme Android we used the following way.
private int[][] states = new int[][] {
new int[] {android.R.attr.state_checked}, // checked
new int[] {-android.R.attr.state_checked}, // unchecked
};
private int[] colors = new int[] {
Color.WHITE, // checked
0 // unchecked set default in onCreate
};
Resources:
- Andorid ColorStateList documentation https://developer.android.com/reference/android/content/res/ColorStateList.html
- StackOverFlow answer for finding the brightness of a color https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color