如何在Android上实现菜单项中的动态值

12

我的操作栏中有一个菜单项。除了菜单项图片外,我还需要显示与其关联的一些数字,这些数字将经常更改。我没有使用Action bar sherlock,也不想使用它。除此之外,其他一切都很好。在所示的图像中,白色图标是我的图标。我需要动态生成带有红色背景的数字。我该如何在Android中实现?

以下是示例图像:

输入图像描述

更新:

我在menu.xml中有这个菜单项。它应该像通知菜单项一样工作,显示通知计数。我设置了菜单图标如下:

 menuItem.setIcon(image);

现在,我需要在菜单项的顶部放置一个文本视图,显示通知的总数。

使用ViewBadger可以实现这个功能吗? Github网址

4个回答

7

5

在 Stack Overflow 上尝试了几乎所有的资源后,我转向了博客; 成功了。我想分享一下对我有用的内容(Api >= 13);来源

让我们从可爱的代码开始,它的使用方式:

 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;
}

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>

这个类方便地制作了一个BadgeDrawable ,它的外观也可以进行修改:

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;
    }
}

这个类帮助设置数字。我建议实现更多的方法来设置徽章,例如日期等:

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);
    }


}

非常重要的一点是,在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>

祝你好运!


你所提到的ic_menu_notifications是层列表文件吗? - Lips_coder
你只是从源代码复制了代码,请停止这样做。 - mahoriR
@Ravi,那不是我做的;源链接已经不能使用了;而且我可以向您保证,在我将其发布到此处之前,这段代码已在我的应用程序中运行过;解释这5个代码块的工作原理很重要。 - msysmilu
链接无法使用。 - Pratik Butani
@PratikButani,没错;这就是为什么我粘贴了代码片段的原因。 - msysmilu
1
我在将BitmapDrawable转换为LayerDrawable时遇到了ClassCastException。请参考以下链接以解决此错误:https://stackoverflow.com/questions/37386027/java-lang-classcastexception-android-graphics-drawable-bitmapdrawable-cannot-be - Virat18

1

这里有一件你可以尝试的事情:

创建一个自定义的Drawable,将图像绘制在背景上,并在图像顶部放置文本。查看this post以获取示例。

然后动态地将此Drawable设置为MenuItem的背景...


0

使用Action View,它适用于默认的ActionBarActionBarSherlock

这里有一个示例

通过这种方法,您只需创建自己的View(例如通过膨胀某些布局),然后可以随意更改背景、内容,如果您的操作视图是ViewGroup的子类,则可以动态添加其他视图等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接