NavigationView menu items with counter on the right

前端 未结 5 843
谎友^
谎友^ 2020-11-27 11:36

The new NavigationView in the new Design Support Library works really great.

They use \"menu-items\" to display th

相关标签:
5条回答
  • 2020-11-27 11:58

    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:

    0 讨论(0)
  • 2020-11-27 12:01

    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");
    }
    
    0 讨论(0)
  • 2020-11-27 12:08

    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+")
    }
    
    0 讨论(0)
  • 2020-11-27 12:20

    Starting from version 23 of appcompat-v7 NavigationView supports action views, so it is quite easy to implement counter yourself.

    1. 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" />
      
    2. 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.

    1. 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.

    0 讨论(0)
  • 2020-11-27 12:20

    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.

    0 讨论(0)
提交回复
热议问题