How to implement dynamic values on menu item in An

2019-02-06 11:47发布

This question already has an answer here:

I have a menu item in the action bar. Along with the menu item image, I need to show some number associated with it which will change often. I am not using Action bar sherlock. I don't want to use that. Other than this everything else just works fine. In the shown image, the white icon color icon is mine. I need to generate the number with the red color background dynamically. How can I do that in Android?

Here is the sample image:

enter image description here

Update:

I have this menu item in my menu.xml. This should work like a notification menu item which shows the number of notification count. I set the menu icon like,

 menuItem.setIcon(image);

Now, on top of the menu item I need to place one text view which has the total count of notifications.

is it possible to implement this functionality with viewbadger? Github url

4条回答
倾城 Initia
2楼-- · 2019-02-06 12:25

I discovered how to add an actionView to a menu item and retrieve as set values to the view in code.

See here: https://stackoverflow.com/a/16648170/857681

查看更多
\"骚年 ilove
3楼-- · 2019-02-06 12:37

Here is one thing you can try:

Create a custom Drawable that paint you image in the background and text on top of the image. Check out this post for sample.

Then set this Drawable as the MenuItem background dynamically...

查看更多
叛逆
4楼-- · 2019-02-06 12:44

After a lot of trying of nearly all resources on SO I turned to blogs; succesfully. I want to share what worked for me (Api >= 13); source.

Let's start with the sweet code, the way it's used:

 public boolean onCreateOptionsMenu(Menu menu) {
    //inflate menu
    getMenuInflater().inflate(R.menu.menu_my, menu);

    // Get the notifications MenuItem and LayerDrawable (layer-list)
    MenuItem item = menu.findItem(R.id.action_notifications);
    LayerDrawable icon = (LayerDrawable) item.getIcon();

    // Update LayerDrawable's BadgeDrawable
    Utils2.setBadgeCount(this, icon, 2);

    return true;
}

The menu_my.xml:

<menu 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"
    tools:context=".MainActivity">
    <item
        android:id="@+id/action_notifications"
        android:icon="@drawable/ic_menu_notifications"
        android:title="Notifications"
        app:showAsAction="always" />
</menu>

This class that conveniently makes a BadgeDrawable; its appearance can be modified as well:

public class BadgeDrawable extends Drawable {

    private float mTextSize;
    private Paint mBadgePaint;
    private Paint mTextPaint;
    private Rect mTxtRect = new Rect();

    private String mCount = "";
    private boolean mWillDraw = false;

    public BadgeDrawable(Context context) {
        //mTextSize = context.getResources().getDimension(R.dimen.badge_text_size);
        mTextSize = 12F;

        mBadgePaint = new Paint();
        mBadgePaint.setColor(Color.RED);
        mBadgePaint.setAntiAlias(true);
        mBadgePaint.setStyle(Paint.Style.FILL);

        mTextPaint = new Paint();
        mTextPaint.setColor(Color.WHITE);
        mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
        mTextPaint.setTextSize(mTextSize);
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextAlign(Paint.Align.CENTER);
    }

    @Override
    public void draw(Canvas canvas) {
        if (!mWillDraw) {
            return;
        }

        Rect bounds = getBounds();
        float width = bounds.right - bounds.left;
        float height = bounds.bottom - bounds.top;

        // Position the badge in the top-right quadrant of the icon.
        float radius = ((Math.min(width, height) / 2) - 1) / 2;
        float centerX = width - radius - 1;
        float centerY = radius + 1;

        // Draw badge circle.
        canvas.drawCircle(centerX, centerY, radius, mBadgePaint);

        // Draw badge count text inside the circle.
        mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
        float textHeight = mTxtRect.bottom - mTxtRect.top;
        float textY = centerY + (textHeight / 2f);
        canvas.drawText(mCount, centerX, textY, mTextPaint);
    }

    /*
    Sets the count (i.e notifications) to display.
     */
    public void setCount(int count) {
        mCount = Integer.toString(count);

        // Only draw a badge if there are notifications.
        mWillDraw = count > 0;
        invalidateSelf();
    }

    @Override
    public void setAlpha(int alpha) {
        // do nothing
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        // do nothing
    }

    @Override
    public int getOpacity() {
        return PixelFormat.UNKNOWN;
    }
}

This class that helps to set the number. I recommend implementing even more thods to set badge as date, etc:

public class Utils2 {
    public static void setBadgeCount(Context context, LayerDrawable icon, int count) {

        BadgeDrawable badge;

        // Reuse drawable if possible
        Drawable reuse = icon.findDrawableByLayerId(R.id.ic_badge);
        if (reuse != null && reuse instanceof BadgeDrawable) {
            badge = (BadgeDrawable) reuse;
        } else {
            badge = new BadgeDrawable(context);
        }

        badge.setCount(count);
        icon.mutate();
        icon.setDrawableByLayerId(R.id.ic_badge, badge);
    }


}

And mui importante a drawable (like a layout) in res/drawable:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/ic_notification"
        android:drawable="@drawable/ice_skate"
        android:gravity="center" />

    <!-- set a place holder Drawable so android:drawable isn't null -->
    <item
        android:id="@+id/ic_badge"
        android:drawable="@drawable/ice_skate" />
</layer-list>

Good lucks!

查看更多
何必那么认真
5楼-- · 2019-02-06 12:45

Use action view. It works with both: default ActionBar and ActionBarSherlock.

Here is an example

With this approach you can just create your own View (by inflating some layout for example) and then do whatever you want (change background, change content, add another views dynamically if your action view is subclass of ViewGroup etc.).

查看更多
登录 后发表回答