The new NavigationView in the new Design Support Library works really great.
They use "menu-items" to display the options.
But how can I display a counter to the right of the menu item?
Like in this picture:
Or like in the GMail app.
Starting from version 23 of appcompat-v7 NavigationView supports action views, so it is quite easy to implement counter yourself.
Create counter layout, i.e. menu_counter.xml:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:textAppearance="#style/TextAppearance.AppCompat.Body2" />
Reference it in your drawer menu xml, i.e. menu/drawer.xml:
<item
...
app:actionLayout="#layout/menu_counter" />
Note that you should use app namespace, don't try to use android.
Alternatively you can manually set action view with MenuItem.setActionView() method.
Find menu item and set counter:
private void setMenuCounter(#IdRes int itemId, int count) {
TextView view = (TextView) navigationView.getMenu().findItem(itemId).getActionView();
view.setText(count > 0 ? String.valueOf(count) : null);
}
Note, that you will need to use MenuItemCompat if you have to support Android 2.x versions.
My workaround was passing a SpannableString with a different background as new title of the MenuItem.
I known is not the best solution and it's not right-aligned but it works as a counter quite well. Something like this:
NavigationView navigation = (NavigationView)findViewById(R.id.navigation);
Menu menuNav = navigation.getMenu();
MenuItem element = menuNav.findItem(R.id.item5);
String before = element.getTitle().toString();
String counter = Integer.toString(5);
String s = before + " "+counter+" ";
SpannableString sColored = new SpannableString( s );
sColored.setSpan(new BackgroundColorSpan( Color.GRAY ), s.length()-(counter.length()+2), s.length(), 0);
sColored.setSpan(new ForegroundColorSpan( Color.WHITE ), s.length()-(counter.length()+2), s.length(), 0);
element.setTitle(sColored);
To improve the counter, here you can find a good answer to set the corners rounded
Example:
Looking at the source for NavigationView, they currently do not support any custom rendering of the menu items (See NavigationMenuPresenter and NavigationMenuAdapter). Hopefully they expose more functionalities soon as I want to set a custom font on the menu items but am unable to without using reflection.
I wanted to have a badge icon for the counters as well. This badge would be pill shaped and have the ability to be different colors to differentiate between important badges and unimportant badges.
To accomplish this, I created a custom view Badge
class Badge #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0,
defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyle, defStyleRes) {
private val badgeText: TextView
private var important: Boolean
init {
inflate(context, R.layout.badge, this)
badgeText = findViewById(R.id.badge)
important = false
isImportant(important)
adjustVisibility()
}
fun setText(text: String) {
badgeText.text = text
adjustVisibility()
}
fun isImportant(isImportant: Boolean) {
if (isImportant) {
badgeText.backgroundTintList = ColorStateList.valueOf(
ContextCompat.getColor(
context,
R.color.nav_badge_important
)
)
} else {
badgeText.backgroundTintList = ColorStateList.valueOf(
ContextCompat.getColor(
context,
R.color.nav_badge_unimportant
)
)
}
}
private fun adjustVisibility() {
if (badgeText.text.isNullOrBlank() && this.visibility == VISIBLE) {
this.visibility = INVISIBLE
} else {
this.visibility = VISIBLE
}
}
}
The layout for the Badge
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/badge"
style="#style/BadgeStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
The style for the Badge
<resources>
<style name="BadgeStyle" parent="Widget.AppCompat.TextView">
<item name="android:textSize">10sp</item>
<item name="android:background">#drawable/badge_curved</item>
<item name="android:textColor">#color/white</item>
</style>
</resources>
The drawable for the Badge
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="300dp" />
<padding
android:bottom="2dp"
android:left="8dp"
android:right="8dp"
android:top="2dp" />
</shape>
For each menu item with the ability to show a Badge, you need to add app:actionViewClass="com.example.ui.Badge" to your Navigation Menu.
The Badge class gives you the ability to set the text and importance of the badge programmatically.
private fun setupBadges(navView: NavigationView) {
val badgesItemOne = navView.menu.findItem(R.id.nav_one).actionView as Badge
val badgesItemTwo = navView.menu.findItem(R.id.nav_two).actionView as Badge
val badgesItemThree = navView.menu.findItem(R.id.nav_three).actionView as Badge
badgesItemOne.setText("6+")
badgesItemOne.isImportant(true)
badgesItemTwo.setText("2")
badgesItemThree.setText("99+")
}
Step 1 :Identify the group item and add “app:actionViewClass=android.widget.TextView” as given below:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_recorder"
app:actionViewClass="android.widget.TextView"
android:icon="#drawable/ic_menu_gallery"
android:title="Gallery" />
<item
android:id="#+id/nav_night_section"
app:actionViewClass="android.widget.TextView"
android:icon="#drawable/ic_menu_slideshow"
android:title="Slideshow" />
</group>
Step 2: Declare the Navigation Drawer menu item and initialize the item with the badge value
//Create these objects above OnCreate()of your main activity
TextView recorder,nightSection;
//These lines should be added in the OnCreate() of your main activity
recorder =(TextView) MenuItemCompat.getActionView(navigationView.getMenu().
findItem(R.id.nav_recorder));
recordSection=(TextView) MenuItemCompat.getActionView(navigationView.getMenu().
findItem(R.id.nav_night_section));
//This method will initialize the count value
initializeCountDrawer();
Step 3: initializeCountDrawer() can be called where ever it’s required. It can also be used to update the count or badge value in the navigation drawer menu item.
private void initializeCountDrawer(){
//Gravity property aligns the text
recorder.setGravity(Gravity.CENTER_VERTICAL);
recorder.setTypeface(null, Typeface.BOLD);
recorder.setTextColor(getResources().getColor(R.color.colorAccent));
recorder.setText("99+");
slideshow.setGravity(Gravity.CENTER_VERTICAL);
slideshow.setTypeface(null,Typeface.BOLD);
slideshow.setTextColor(getResources().getColor(R.color.colorAccent));
//count is added
slideshow.setText("7");
}
Related
I'm developing a NavigationRail and I wanted to display the text of each item in two lines, as show in this official example, but it keeps getting ellipsized in the end. I've tried to redefine the applying style but nothing seems to work.
Any help? Thanks in advance!
As per the Navigation rail - Material Design documentation it seems that there is no an official way to set multiple lines for an item text. But you can achieve this with a simple workaround like in the below example:
1.Define the NavigationRailView in xml like the below:
<com.google.android.material.navigationrail.NavigationRailView
android:id="#+id/navigation_rail"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:labelVisibilityMode="labeled"
app:menu="#menu/navigation_rail_menu"/>
where #menu/navigation_rail_menu contains the below sample menu items:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/menu_item_all_files"
android:enabled="true"
android:icon="#android:drawable/ic_menu_gallery"
android:title="All\nFiles" />
<item
android:id="#+id/menu_item_recent"
android:enabled="true"
android:icon="#android:drawable/ic_menu_slideshow"
android:title="Recent\nFiles" />
<item
android:id="#+id/menu_item_all_pictures"
android:enabled="true"
android:icon="#android:drawable/ic_menu_gallery"
android:title="All\nPictures" />
</menu>
2.And for each item change the Max number of lines in a programmatically way like in the below example:
//get the NavigationRailView
NavigationRailView navigationRailView = findViewById(R.id.navigation_rail);
//menu item 1
NavigationBarItemView item1 = navigationRailView.findViewById(R.id.menu_item_all_files);
BaselineLayout item1BaselineLayout = item1.findViewById(R.id.navigation_bar_item_labels_group);
setItemMaxLines(item1BaselineLayout, 2);
//menu item 2
NavigationBarItemView item2 = navigationRailView.findViewById(R.id.menu_item_recent);
BaselineLayout item2BaselineLayout = item2.findViewById(R.id.navigation_bar_item_labels_group);
setItemMaxLines(item2BaselineLayout, 2);
//menu item 3
NavigationBarItemView item3 = navigationRailView.findViewById(R.id.menu_item_all_pictures);
BaselineLayout item3BaselineLayout = item3.findViewById(R.id.navigation_bar_item_labels_group);
setItemMaxLines(item3BaselineLayout, 2);
where setItemMaxLines() is a helper function to change for each Item the MaxLines:
private void setItemMaxLines(BaselineLayout baselineLayout, int maxLines){
if(baselineLayout!=null){
for(int i=0; i<baselineLayout.getChildCount(); i++){
View child = baselineLayout.getChildAt(i);
if(child instanceof MaterialTextView){
((MaterialTextView)child).setMaxLines(maxLines);
((MaterialTextView)child).setGravity(Gravity.CENTER);
}
}
}
}
Result:
I am trying to create a custom button with progress bar inside of it in Android.
The button should have 2 states:
Normal and Loading.
In Normal state it should show a text while in Loading state it should show a centerred circular progress indicator instead of the text!
When the button state returns to "Normal" state it should show the text again.
To achieve this, I've thought about create a custom view which build from a RelativeLayout
and inside of it there is a TextView and a Circular progress indicator and change their visibility in code according to the state.
This idea and logic works pretty good.
Please refer to images of my buttons with the progress indicators:
However, the problem comes when I want to apply a selector to this view,
I've created a style and a selector for each button but it just not setting the right background to the view when its disabled.
A RelativeLayout doesn't has an enabled attribute available in its xml so I had to add a styleable attr and change its state in code with isEnabled = false or something like that.
This makes it disabled in did, but the background stays as it is enabled (The selector not working).
This is my "Button" source code:
class ProgressButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
private val progressBar: LottieAnimationView
private val buttonTextView: TextView
init {
val root = LayoutInflater.from(context).inflate(R.layout.progress_button, this, true)
buttonTextView = root.findViewById(R.id.button_text)
progressBar = root.findViewById(R.id.progress_indicator)
loadAttr(attrs, defStyleAttr)
}
private fun loadAttr(attrs: AttributeSet?, defStyleAttr: Int) {
val arr = context.obtainStyledAttributes(
attrs,
R.styleable.ProgressButton,
defStyleAttr,
0
)
val buttonText = arr.getString(R.styleable.ProgressButton_text)
val loading = arr.getBoolean(R.styleable.ProgressButton_loading, false)
val enabled = arr.getBoolean(R.styleable.ProgressButton_enabled, true)
isEnabled = enabled
arr.recycle()
buttonTextView.text = buttonText
setLoading(loading)
}
fun setLoading(loading: Boolean){
if(loading){
buttonTextView.visibility = View.GONE
progressBar.visibility = View.VISIBLE
} else {
buttonTextView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
}
}
}
This its layout:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:id="#+id/button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textAppearance="?android:attr/textAppearanceButton"
android:text="OK" />
<com.airbnb.lottie.LottieAnimationView
android:id="#+id/progress_indicator"
android:layout_width="#dimen/progressbar_width"
android:layout_height="#dimen/progressbar_width"
android:layout_centerInParent="true"
android:visibility="gone"
app:lottie_autoPlay="true"
app:lottie_loop="true"
app:lottie_rawRes="#raw/lottile_button_loader" />
</RelativeLayout>
This a the background with selector for it:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="#dimen/components_corner_radius" />
<solid android:color="#color/button_black_bg_selector" />
</shape>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/black" android:state_enabled="true" />
<item android:color="#color/buttons_black_pressed" android:state_pressed="true" />
<item android:color="#color/buttons_black_disabled" android:state_enabled="false" />
<item android:color="#color/black" />
This is the styling and theme:
<style name="Theme.Widget.ProgressButton" parent="">
<item name="android:textAppearanceButton">#style/TextAppearance.Body.White</item>
</style>
<style name="Widget.ProgressButton.Black" parent="#style/Theme.Widget.ProgressButton">
<item name="android:colorControlHighlight">#color/buttons_black_pressed</item>
<item name="android:background">#drawable/progress_button_black</item>
</style>
And finally, this how i use it in a fragment layout xml:
<com.example.widgets.ProgressButton
android:id="#+id/button_black_loading"
android:theme="#style/Widget.ProgressButton.Black". //This is where it gets its style and theme
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:loading="true"/>
Any help will be appreciated.
Finally I've came to a pattern that seems to work with a single style line in the custom view usage xml (e.g. Fragment or Activity layout).
For each button I've defined similar styling blocks that looks like this:
<style name="Theme.Widget.Button.Black" parent="">
<item name="android:textAppearanceButton">#style/TextAppearance.BlackButton</item> //This will set the theme for the button internal TextView
<item name="android:colorControlHighlight">#color/buttons_black_pressed</item> //This will set the highlight color for ripple effect
</style>
<style name="Widget.Button.Black" parent="">
**<item name="android:theme">#style/Theme.Widget.Button.Black</item>** //Note this theme attribute which takes that above styling and applying it as a theme!!
<item name="android:background">#drawable/button_black</item> //A shape with selector drawable
</style>
The background drawable:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight"> //This comes from the theme for the ripple effect
<item android:drawable="#drawable/button_black_shape"/> //The selector
</ripple>
The background shape drawable:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="#dimen/components_corner_radius" />
<solid android:color="#color/button_black_bg_selector" />
</shape>
The selector:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#color/black" android:state_enabled="true" />
<item android:color="#color/buttons_black_pressed" android:state_pressed="true" />
<item android:color="#color/buttons_black_disabled" android:state_enabled="false" />
<item android:color="#color/black" />
</selector>
And finally using the button in fragment XML like this:
<com.sample.widgets.ProgressButton
android:id="#+id/button_black_enabled"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:enabled="true"
app:text="OK"
style="#style/Widget.Button.Black"/> //The style brings a theme also!
After adding the selector you need to change the state of ProgressButtonI am adding essential code below which should work.
Selector should be like :-
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/black" android:state_enabled="true" />
<item android:drawable="#color/buttons_black_pressed" android:state_pressed="true" />
<item android:drawable="#color/buttons_black_disabled" android:state_enabled="false" />
and ProgressButton.kt
class ProgressButton #JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {
private val progressBar: LottieAnimationView
private val buttonTextView: TextView
init {
val root = LayoutInflater.from(context).inflate(R.layout.progress_button, this, true)
buttonTextView = root.findViewById(R.id.button_text)
progressBar = root.findViewById(R.id.progress_indicator)
loadAttr(attrs, defStyleAttr)
}
private fun loadAttr(attrs: AttributeSet?, defStyleAttr: Int) {
// this line can be removed if you are setting selector in xml
setBackgroundResource(R.drawable.button_selector)
setLoading(true)
}
fun setLoading(loading: Boolean) {
if (loading) {
buttonTextView.visibility = View.GONE
progressBar.visibility = View.VISIBLE
} else {
buttonTextView.visibility = View.VISIBLE
progressBar.visibility = View.GONE
}
isEnabled = !loading
}
}
I am looking for a way to programatically change my item colors in my BottomNavigationView.
I found out how to change icons color, i did it as following :
fun setMenu(selected: Int) {
bottomNavigationMenu?.let {
it.menu.findItem(R.id.bottom_menu_home).icon
.setColorFilter(getMenuColor(R.id.bottom_menu_home, selected), PorterDuff.Mode.SRC_ATOP)
// more items
it.menu.findItem(R.id.bottom_menu_fidelity)?.icon
?.setColorFilter(getMenuColor(R.id.bottom_menu_fidelity, selected), PorterDuff.Mode.SRC_ATOP)
}
}
fun getMenuColor(id: Int, selected: Int): Int {
if (Singletons.restaurant.title.isBlank())
getRestaurant()
else {
if (id == selected) return (Singletons.restaurant.color)
else return ContextCompat.getColor(this, R.color.grey7E)
}
return (0)
}
Now I am looking for how to change the title color.
I am looking for something like
it.menu.findItem(R.id.bottom_menu_home).title // etc
but I can't find a correct function to do it.
Here is my items from main_bottom_menu.xml :
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/bottom_menu_home"
android:enabled="true"
android:icon="#drawable/ic_home"
android:iconTint="#color/cardview_dark_background"
android:title="#string/bottom_menu_home"
android:visible="false"
app:showAsAction="ifRoom" />
<!-- 3 more items -->
<item
android:id="#+id/bottom_menu_profile"
android:enabled="true"
android:icon="#drawable/ic_profile"
android:iconTint="#color/cardview_dark_background"
android:title="#string/bottom_menu_profile"
android:visible="false"
app:showAsAction="ifRoom" />
</menu>
Oddly, the text color is equal to my colorPrimary, so it has to be set somewhere.
The goal is to dynamically set a color (from an API).
Any idea of where was my title color set ?
To set the color of all items, you could simply call setItemTextColor() on your BottomNavigationView instance.
To set them individually, you could use a SpannableString:
val titleSpannable = SpannableString("title")
titleSpannable.setSpan(
ForegroundColorSpan(Color.parseColor("#ffffff")),
0,
titleString.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
bottomNavigationView.menu.findItem(R.id.your_item_id).title = titleSpannable
I have implemented the bottom navigation view in my app and I have looked every where to display badges on top of the icons like this
I was wondering whether this is even possible to implement. Any help is appreciated.
Thank you.
If you just want to use a stock BottomNavigationView and no third party lib here's how I've done it:
BottomNavigationMenuView bottomNavigationMenuView =
(BottomNavigationMenuView) navigationView.getChildAt(0);
View v = bottomNavigationMenuView.getChildAt(3);
BottomNavigationItemView itemView = (BottomNavigationItemView) v;
View badge = LayoutInflater.from(this)
.inflate(R.layout.notification_badge, itemView, true);
Then here's the layout file:
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:id="#+id/notifications.badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:layout_marginLeft="10dp"
android:layout_marginStart="10dp"
android:background="#drawable/notification_badge"
android:gravity="center"
android:padding="3dp"
android:text="9+"
android:textColor="#color/white"
android:textSize="11sp" />
</merge>
Then just find TextView by id and set text.
#drawable/notification_badge is just a circle shape drawable
Adding badges is natively supported now, using the latest material dependency
add this to your build.gradle
implementation 'com.google.android.material:material:1.1.0-alpha09'
in your layout add this
<!-- The rest of your layout here ....-->
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:menu="#menu/bottom_nav_menu"
/>
then you can just
val navBar = findViewById<BottomNavigationView>(R.id.bottom_navigation)
navBar.getOrCreateBadge(R.id.action_add).number = 2
R.id.action_add for you would be the id of the menu item you want to put a badge on. Check it from the menu file you feed to the BottomNavigationView.
Make sure your app theme is in Theme.MaterialComponents
you can check it in styles or manifest.
for this example mine was this
<style name="AppTheme" parent="Theme.MaterialComponents.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">#color/colorPrimary</item>
<item name="colorPrimaryDark">#color/colorPrimaryDark</item>
<item name="colorAccent">#color/colorAccent</item>
<item name="android:statusBarColor" tools:targetApi="lollipop">#color/colorPrimary</item>
</style>
Edit 2020:
Use BottomNavigation from material components instead, it gives
support to add badges on items and many other features out of the box:
https://github.com/material-components/material-components-android/blob/master/docs/components/BottomNavigation.md
Old Answer:
When using support library Bottom Navigation bar, its quite complex to show a badge/notification on menu items.
However there are easy solutions to get it done. Such as
https://github.com/aurelhubert/ahbottomnavigation
This library is more advanced version of Bottom Navigation bar. And you can set a badge on menu item simply using this code snippet.
bottomNavigation.setNotification(notification, bottomNavigation.getItemsCount() - 1);
And you'll get following result
EDIT 2:
BottomNavigationView now supports showing badge natively, as said in the doc here.
bottomNavigation.getOrCreateBadge(menuItemId)
I was facing the same issue and I didn't want to use a library.
So I created a custom layout called layout_news_badge:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/badge_frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/badge_text_view"
android:layout_width="19dp"
android:layout_height="19dp"
android:textSize="11sp"
android:textColor="#android:color/white"
android:background="#drawable/news_bottom_nav_bg"
android:layout_gravity="top"
android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
android:gravity="center"
android:padding="2dp"
tools:text="9+" />
</FrameLayout>
TextView background(news_bottom_nav_bg):
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="?attr/colorPrimary" />
</shape>
Then I created a BottomMenuHelper with this 2 methods:
public static void showBadge(Context context, BottomNavigationView
bottomNavigationView, #IdRes int itemId, String value) {
removeBadge(bottomNavigationView, itemId);
BottomNavigationItemView itemView = bottomNavigationView.findViewById(itemId);
View badge = LayoutInflater.from(context).inflate(R.layout.layout_news_badge, bottomNavigationView, false);
TextView text = badge.findViewById(R.id.badge_text_view);
text.setText(value);
itemView.addView(badge);
}
public static void removeBadge(BottomNavigationView bottomNavigationView, #IdRes int itemId) {
BottomNavigationItemView itemView = bottomNavigationView.findViewById(itemId);
if (itemView.getChildCount() == 3) {
itemView.removeViewAt(2);
}
}
Then when I call it in my Activity:
BottomMenuHelper.showBadge(this, mBottomNavigationView, R.id.action_news, "1");
EDIT 1:
Added improvement by suggestion jatin rana
Update: now material support badge, see more below
material baging
bottom navigation
val badge = bottomNavigation.getOrCreateBadge(menuItemId)
badge.isVisible = true
// An icon only badge will be displayed unless a number is set:
badge.number = 99
Old answer
base on #Tinashe's answer, i'd like badge show as bellow without number:
code:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
// position = 2
addBadge(POSITION_HISTORY)
}
/**
* add badge(notification dot) to bottom bar
* #param position to get badge container
*/
#SuppressLint("PrivateResource")
private fun addBadge(position: Int) {
// get badge container (parent)
val bottomMenu = navigation.getChildAt(0) as? BottomNavigationMenuView
val v = bottomMenu?.getChildAt(position) as? BottomNavigationItemView
// inflate badge from layout
badge = LayoutInflater.from(this)
.inflate(R.layout.badge_layout, bottomMenu, false)
// create badge layout parameter
val badgeLayout: FrameLayout.LayoutParams = FrameLayout.LayoutParams(badge?.layoutParams).apply {
gravity = Gravity.CENTER_HORIZONTAL
topMargin = resources.getDimension(R.dimen.design_bottom_navigation_margin).toInt()
// <dimen name="bagde_left_margin">8dp</dimen>
leftMargin = resources.getDimension(R.dimen.bagde_left_margin).toInt()
}
// add view to bottom bar with layout parameter
v?.addView(badge, badgeLayout)
}
badge_layout.xml (badge_size=12dp)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="#dimen/badge_size"
android:layout_height="#dimen/badge_size"
android:background="#drawable/new_notification" />
and drawable background new_notification.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<corners android:radius="100dp"/>
<solid android:color="#F44336"/>
</shape>
Badge has now been added as a part of AndroidX BottomNavigationView by BadgeDrawable.
See docs
fun setBadge(count: Int) {
if (count == 0) {
bottomNavigationView.removeBadge(R.id.ticketsNavigation)
} else {
val badge = bottomNavigationView.getOrCreateBadge(R.id.ticketsNavigation) // previously showBadge
badge.number = count
badge.backgroundColor = getColor(R.color.badge)
badge.badgeTextColor = getColor(R.color.blackTextColor)
}
}
// Menu:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/ticketsNavigation"
android:icon="#drawable/vector_drawable_navbar_tickets"
android:title="#string/tickets_title"/>
...
</menu>
Edit:
As noted in the comments it should be possible to just update the badge count without needing to add or remove the badge all the time like this:
fun setBadge(count: Int) {
bottomNavigationView.getBadge(menuItemId)?.isVisible = count > 0
}
As #zxbin answer. you can check BadgeView and try below code
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(this);
navigation.setSelectedItemId(R.id.navigation_store);
BottomNavigationMenuView bottomNavigationMenuView =
(BottomNavigationMenuView) navigation.getChildAt(0);
View v = bottomNavigationMenuView.getChildAt(4); // number of menu from left
new QBadgeView(this).bindTarget(v).setBadgeNumber(5);
source from my gist
A simple way:
As Material Design updated their library and according to
https://medium.com/over-engineering/hands-on-with-material-components-for-android-bottom-navigation-aae2aa9066be
I was able to update (or create my BottomNavigationView Badge) from inside my recycler adapter (in a fragment) without any external lib.
Initial State:
So, as in adapter i got the Context from my activity i access it and recover the instance of bottom navigation:
navBottomView = ((AppCompatActivity)this.context).findViewById(R.id.nav_view);
check if the badge is null (not created yet), if is, set it to quantity choosed:
BadgeDrawable badgeDrawable = navBottomView.getBadge(R.id.navigation_carrinho);
if (badgeDrawable == null)
navBottomView.getOrCreateBadge(R.id.navigation_carrinho).setNumber(item.getQuantidade());
otherwise get the previous quantity and increase the badge value:
int previousValue = badgeDrawable.getNumber();
badgeDrawable.setNumber(previousValue + item.getQuantidade());
Don't forget the imports:
import com.google.android.material.badge.BadgeDrawable;
import com.google.android.material.bottomnavigation.BottomNavigationView;
Final State:
All in One with add to cart button listener:
btnAddCarrinho.setOnClickListener(v -> {
navBottomView = ((AppCompatActivity) this.context).findViewById(R.id.nav_view);
BadgeDrawable badgeDrawable = navBottomView.getBadge(R.id.navigation_carrinho);
if (badgeDrawable == null) {
navBottomView.getOrCreateBadge(R.id.navigation_carrinho).setNumber(item.getQuantidade());
} else {
int previousValue = badgeDrawable.getNumber();
badgeDrawable.setNumber(previousValue + item.getQuantidade());
}
});
Please try this once.
1) Create xml file for badge (ex. notification_badge_view.xml)
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/badge"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="top|center_horizontal"
android:layout_marginStart="10dp"
android:gravity="center"
android:padding="3dp"
app:srcCompat="#drawable/notification_badge" />
</FrameLayout>
2) Create drawable file for notification dot shape (ex. badge_circle.xml)
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#color/colorAccent" />
<stroke
android:width="2dp"
android:color="#android:color/white" />
</shape>
3) In your activity onCreate method add the badge view to BottomNavigationView
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_landing);
addBadgeView();
}
4) And the addBadgeView method is below
private void addBadgeView() {
try {
BottomNavigationMenuView menuView = (BottomNavigationMenuView) bottomNavigationBar.getChildAt(0);
BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(0); //set this to 0, 1, 2, or 3.. accordingly which menu item of the bottom bar you want to show badge
notificationBadge = LayoutInflater.from(LandingActivity.this).inflate(R.layout.view_notification_badge, menuView, false);
itemView.addView(notificationBadge);
notificationBadge.setVisibility(GONE);// initially badge will be invisible
} catch (Exception e) {
e.printStackTrace();
}
}
Note: bottomNavigationBar is your bottom bar view.
5) Refresh badge to show and hide by following method
private void refreshBadgeView() {
try {
boolean badgeIsVisible = notificationBadge.getVisibility() != GONE;
notificationBadge.setVisibility(badgeIsVisible ? GONE : VISIBLE);//makes badge visible and invisible
} catch (Exception e) {
e.printStackTrace();
}
}
6) And finely make hide when we clicking on particular bottom bar page by following line.
bottomNavigationBar.setOnNavigationItemSelectedListener(new
BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem menuItem)
{
switch (menuItem.getItemId()) {
case R.id.bottom_bar_one:
//while moving to first fragment
notificationBadge.setVisibility(GONE);
break;
case R.id.bottom_bar_two:
//moving to second fragment
break;
case R.id.bottom_bar_three:
//moving to third fragment
break;
}
return true;
}
});
#Abel's answer is the best unless you already have a complex set of themes and don't have the time to change them all.
However, if a) you are pressed for time and if you are using the Google Material library BottomNavigationView Bar or b) you want to add your own custom view badge - then the accepted answer won't work with com.google.android.material:material:1.1.0
You will need to code for a different view hierarchy than the accepted answer
BottomNavigationItemView itemView = (BottomNavigationItemView) ((BottomNavigationMenuView) mBottomNavigation.getChildAt(0)).getChildAt(2);
View badge = LayoutInflater.from(this).inflate(R.layout.navigation_dot, itemView, false);
itemView.addView(badge);
if you do want to update your theme and update to
com.google.android.material:material:1.1.0-alpha09
then all you need to do instead, is
mBottomNavigation.getOrCreateBadge(R.id.navigation_menu_item_one).setNumber(YOUR_NUMBER);
The remove and number functions are only present in the 1.1.0-alpha09 version (and higher)
You can try this way:
Put a TextView inside the BottomNavigationView for counting (BottomNavigationView is a FrameLayout):
<android.support.design.widget.BottomNavigationView android:id="#id/bottomMenu" style="#style/bottomMenu">
<TextView android:id="#id/bottomMenuSelectionsNumber" style="#style/bottomMenuSelectionsNumber"/>
</android.support.design.widget.BottomNavigationView>
And style them like this:
<style name="bottomMenu">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">#dimen/toolbarHeight</item>
<item name="android:layout_gravity">center|bottom</item>
<item name="android:background">#color/colorThird</item>
<item name="itemBackground">#drawable/tabs_ripple</item>
<item name="itemIconTint">#drawable/bottom_menu_item_color</item>
<item name="itemTextColor">#drawable/bottom_menu_item_color</item>
<item name="menu">#menu/bottom_menu</item>
</style>
<style name="bottomMenuSelectionsNumber">
<item name="android:text">#string/bottomMenuSelectionsNumber</item>
<item name="android:textSize">#dimen/appSecondFontSize</item>
<item name="android:textColor">#color/white</item>
<item name="android:layout_width">#dimen/bottomMenuSelectionsNumberDim</item>
<item name="android:layout_height">#dimen/bottomMenuSelectionsNumberDim</item>
<item name="android:layout_gravity">right|bottom</item>
<item name="android:layout_marginRight">#dimen/bottomMenuSelectionsNumberMarginR</item>
<item name="android:layout_marginBottom">#dimen/bottomMenuSelectionsNumberMarginB</item>
<item name="android:gravity">center</item>
<item name="android:includeFontPadding">false</item>
<item name="android:background">#drawable/bottom_menu_selections_number_bg</item>
</style>
And bottom_menu_selections_number_bg:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#color/colorAccent"/>
<corners android:radius="#dimen/cornerRadius"/>
</shape>
Have a look in at the documentation page:
https://material.io/develop/android/components/bottom-navigation-view/
TL;DR:
They didn't update the correct methods to use, so they left a small error on the documentation. To add or remove a badge do as follows:
// to remove
bottomNavigationView.removeBadge(R.id.action_settings)
// to add
bottomNavigationView.getOrCreateBadge(R.id.action_settings).apply {
//if you want to change other attributes, like badge color, add a number, maximum number (a plus sign is added, e.g. 99+)
number = 100
maxCharactersCount = 3
backgroundColor = ContextCompat.getColor(context, R.color.color_red)
}
Here's a simple way to create & remove badge count with material bottom navigation.
public class BadgeIconHelper {
public static void showNotificationBadge(BottomNavigationView
bottomNavigationView, #IdRes int itemId, String value) {
BadgeDrawable badge = bottomNavigationView.getOrCreateBadge(itemId);
badge.setBackgroundColor(ContextCompat.getColor(bottomNavigationView.getContext(), R.color.color_primary));
badge.setBadgeTextColor(ContextCompat.getColor(bottomNavigationView.getContext(), R.color.color_white));
badge.setMaxCharacterCount(3);
badge.setVerticalOffset(2);
badge.setVisible(true);
badge.setNumber(Integer.parseInt(value));
}
public static void removeNotificationBadge(BottomNavigationView bottomNavigationView, #IdRes int itemId) {
BadgeDrawable badgeDrawable = bottomNavigationView.getBadge(itemId);
if (badgeDrawable != null) {
badgeDrawable.setVisible(false);
badgeDrawable.clearNumber();
}
}
}
Using support library BottomNavigationView is difficult. An easy solution is using external components.
One easy to handle is: https://github.com/roughike/BottomBar
Checking its documentation it's as easy as:
BottomBarTab nearby = bottomBar.getTabWithId(R.id.tab_nearby);
nearby.setBadgeCount(5);
// Remove the badge when you're done with it.
nearby.removeBadge/();
If you want only dot without number, then simply you can create bottom navigation using com.google.android.material.bottomnavigation.BottomNavigationView
and in java
BottomNavigationView mBtmView = (BottomNavigationView) findViewById(R.id.bottom_navigatin_view);
mBtmView.setOnNavigationItemSelectedListener(this);
mBtmView.getOrCreateBadge(R.id.chatFragment).setBackgroundColor(getResources().getColor(R.color.Red));
i did some changes answer of #ilbose i did in this way and tested small and big screen sizes
../drawable/badge_circle.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
<solid android:color="#color/solid_red_base" />
and ../layout/notifcation_badge.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/badge_frame_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="11dp"
android:layout_gravity="center_horizontal">
<TextView
android:id="#+id/badge_text_view"
android:layout_width="12dp"
android:layout_height="12dp"
android:textSize="11sp"
android:textColor="#android:color/white"
android:background="#drawable/message_badge"
android:layout_gravity="top"
android:layout_centerHorizontal="true"
android:padding="2dp"/> </RelativeLayout>
and in java code
public static void showBadge(Context context, BottomNavigationView
bottomNavigationView, #IdRes int itemId, String value) {
BottomNavigationItemView itemView = bottomNavigationView.findViewById(itemId);
View badge = LayoutInflater.from(context).inflate(R.layout.message_notification_badge, bottomNavigationView, false);
TextView text = badge.findViewById(R.id.badge_text_view);
text.setText(value);
itemView.addView(badge);
}
public static void removeBadge(BottomNavigationView bottomNavigationView, #IdRes int itemId) {
BottomNavigationItemView itemView = bottomNavigationView.findViewById(itemId);
if (itemView.getChildCount() == 4) {
itemView.removeViewAt(4);
}
}
Firstly create a layout file of your badge, then follow these steps
BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigation.getChildAt(0);
BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(2);
View messageBadgeView = LayoutInflater.from(this).inflate(R.layout.message_badge_view, menuView, false);
TextView textView = messageBadgeView.findViewById(R.id.counter_badge);
textView.setText("15");
itemView.addView(messageBadgeView);`
I used Android Studio to implement the Navigation Drawer and I can't get the blue colour that is used to show which section we're currently in to change.
I've tried numerous things, I'm currently using a listSelector which looks like:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true" android:drawable="#color/selected" />
<item android:state_pressed="true" android:drawable="#color/highlight" />
</selector>
I've also tried state_checked. state_pressed works in this situation but the currently selected item is still blue.
EDIT:
I've been examining this more and when the adapter is created the context that is passed is getActionBar().getThemedContext() so I'm thinking if I can find the right attribute to assign to my actionbar style I can change it from there. I've tried a few different attributes with no luck. Does anyone know the exact attribute?
I've also realised if I put
<item name="android:activatedBackgroundIndicator">#drawable/nav_listview_selector</item>
in the main part of my theme and change getActionBar().getThemedContext() for getActivity.getBaseContext then I can change the color but I don't think this is the correct way. I think the themed context should be used. So if anyone knows where the activatedBackgroundIndicator could be put so that it would be used in getActionBar.getThemedContext()
EDIT2:
So the text view used for the listview is one within the SDK it looks like this:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceListItemSmall"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>
So I tried modifying the "?android:attr/activatedBackgroundIndicator" at the theme level but it has no effect for checked/selected/activated but it does for pressed. Does anyone know why this is? And how I can change it?
To solve this problem:
1- You don't need android:listSelector under your ListView.
2- Open (or Create) styles.xml under (res/values).
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:activatedBackgroundIndicator">#drawable/drawer_list_selector</item>
</style>
3- Under res/drawable folder create drawer_list_selector.xml file
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="#drawable/light_gray_color" />
<item android:state_activated="true" android:drawable="#drawable/red_color" />
<item android:drawable="#android:color/transparent" />
</selector>
4- Under res/drawable create red_color.xml / light_gray_color.xml (or any other name) and add your desired Hex color:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#C8FF0000"/>
</shape>
5- Open your project AndroidManifest.xml and add android:theme tag (if not exist)
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
Reference / Credit: Changing Navigation Drawer Selected Item Color from default blue
To change the "Navigation Drawer item background colour for selected item" you could do it with the attribut:
colorControlHighlight
In your "styles.xml" it could look like this:
<style name="YourStyleNameFor.NavigationDrawer" parent="ThemeOverlay.AppCompat.Light">
<item name="colorControlHighlight">#color/your_highlight_color</item>
</style>
Don't forget to apply your Style in the tag:
android.support.design.widget.NavigationView
For example in your activity_main.xml it could look like this:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/navigationdrawer_header"
<!-- the following line referes to your style -->
app:theme="#style/YourThemeNameFor.NavigationDrawer"
<!-- the following two lines are maybe also interesting for you -->
app:itemIconTint="#color/gray3"
app:itemTextColor="#color/gray3"
app:menu="#menu/navigationdrawer_main" />
This is working for me:
First define a drawable item_bg.xml as:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="#drawable/nav_menu_bg" />
</selector>
Then use this drawable in navigation_main_layout.xml as:
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:itemBackground="#drawable/item_bg"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_navigation"
app:menu="#menu/navigation_main_layout_drawer" />
here is how i have done and it is working, the brief concept is maintain the position of selected item in adapter and call notifyDataSetChanged on calling notifyDatasetChanged the getView method is called again and in get view check the position on the selected position change the background view. Here is the code :
Adapter of NavigationDrawer List View
public class MenuAdapter extends BaseAdapter {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private Context mContext;
private String name;
private int profile;
private int mIcons[];
private int selectedPosition = 0;
private String mNavTitles[];
private LayoutInflater mInflater;
public MenuAdapter(String titles[], int icon[], String Name, int profile) {
mNavTitles = titles;
mIcons = icon;
name = Name;
this.profile = profile;
}
public MenuAdapter(String Titles[], int Icons[], Context mContext) {
mNavTitles = Titles;
mIcons = Icons;
this.mContext = mContext;
mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return mNavTitles.length;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(R.layout.item_row, parent, false);
TextView textView = (TextView) convertView.findViewById(R.id.rowText);
ImageView imageView = (ImageView) convertView.findViewById(R.id.rowIcon);
final LinearLayout layout = (LinearLayout) convertView.findViewById(R.id.outerLayout);
imageView.setImageResource(mIcons[position]);
textView.setText(mNavTitles[position]);
if (position == selectedPosition)
layout.setBackgroundColor(mContext.getResources().getColor(R.color.app_bg));
else
layout.setBackgroundColor(mContext.getResources().getColor(R.color.normal_bg));
return convertView;
}
public void setSelectedPosition(int position) {
this.selectedPosition = position;
}
}
in your activity do this
private class DrawerItemClickListener implements ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
mMenuAdapter.setSelectedPosition(position - 1);
mMenuAdapter.notifyDataSetChanged();
}
}
if anyone still face any difficulty, feel free to ask.
I have implement drawer menu with custom adapter class. May be it will help someone Drawer List
<ListView
android:id="#+id/listview_drawer"
android:layout_width="260dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/menu_item_color"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:fadingEdge="none"
/>
drawer_list_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/menu_selector"
>
<ImageView
android:id="#+id/imgIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp"
android:src="#drawable/ic_menu_home" />
<TextView
android:id="#+id/lblName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_toRightOf="#+id/imgIcon"
android:minHeight="48dp"
android:textColor="#color/menu_txt_color" />
menu_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="#android:integer/config_mediumAnimTime">
<!-- selected -->
<item android:drawable="#color/menu_item_active_color" android:state_focused="true" android:state_pressed="false"/>
<item android:drawable="#color/menu_item_active_color" android:state_pressed="true"/>
<item android:drawable="#color/menu_item_active_color" android:state_activated="true"/>
<item android:drawable="#color/menu_item_active_color" android:state_checked="true"/>
<item android:drawable="#color/menu_item_active_color" android:state_selected="true"/>
<item android:drawable="#color/menu_item_color" android:state_activated="false"/>
Add this on item click listner of listview
yourlistview.setItemChecked(position, true);
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/list_item_back_pressed" android:state_pressed="true" />
<item android:state_activated="true"><color android:color="#color/primary_blue"/></item>
<item android:drawable="#color/list_item_back_normal"/>
</selector>
In addition to providing a custom selector drawable for the listSelector, you should also set the background resource of the list item to a similar selector drawable that has different drawables for the different states.
I usually use my custom adapter that has an int selection field, and a setSelection(int) function. And in the getView function I set the background of the view according to position == selection.
Still not sure why it is that it doesn't work. But the way I found around it is to use my own simple_list_item_activated layout to be passed to the ArrayAdapter which was basically the same except for setting the text colour to white. I then replaced getActionBar().getThemedContext() with getActivity().getBaseContext() and it now has an effect.
This may not be the correct way and may have repercussions in the future, but for now I have it working the way I want it to.
I know its too late but I have solved this issue in my app.
Pls dont think it is silly, just simply change the position of "state_pressed" to top.
<item android:drawable="#drawable/list_item_bg_pressed" android:state_pressed="true"/>
<item android:drawable="#drawable/list_item_bg_normal" android:state_activated="false"/>
<item android:drawable="#drawable/list_item_bg_selected" android:state_activated="true"/>
In Future if anyone comes here using, Navigation Drawer Activity (provided by Studio in Activity Prompt window)
The answer is -
Use this before OnCreate() in MainActivity
int[][] state = new int[][] {
new int[] {android.R.attr.state_checked}, // checked
new int[] {-android.R.attr.state_checked}
};
int[] color = new int[] {
Color.rgb(255,46,84),
(Color.BLACK)
};
ColorStateList csl = new ColorStateList(state, color);
int[][] state2 = new int[][] {
new int[] {android.R.attr.state_checked}, // checked
new int[] {-android.R.attr.state_checked}
};
int[] color2 = new int[] {
Color.rgb(255,46,84),
(Color.GRAY)
};
ColorStateList csl2 = new ColorStateList(state2, color2);
and use this in onNavigationItemSelected() in MainActivity (you dont need to Write this function if you use Navigation Drawer activity, it will be added in MainActivity).
NavigationView nav = (NavigationView) findViewById(R.id.nav_view);
nav.setItemTextColor(csl);
nav.setItemIconTintList(csl2);
nav.setItemBackgroundResource(R.color.white);
Tip - add this code before If else Condition in onNavigationItemSelected()
This worked for me :
implemented menu drawer not by populating the navigation view with list, but with menu items.
created a drawable like this :
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/drawer_menu_selector_color" android:state_checked="true"></item>
<item android:drawable="#color/drawer_menu_selector_color" android:state_activated="true"></item>
and in onCreate method , set the id of the menu item which corresponds to selected activity as checked.
and implement the drawable selector file to your navigation drawer like this
app:itemBackground="#drawable/drawer_menu_selector"
fyi : need to define your 'app' namespace.
I searched for solution on this issue, tried everything, and only this solution worked for me.
You can find it on this link https://tuchangwei.github.io/2016/07/18/The-solution-that-the-menu-item-of-Navigation-View-can-t-change-its-background-When-it-is-selected-checked/
All the credit to https://tuchangwei.github.io/