在Android中为汉堡包导航菜单图标添加徽章计数器

时间:2017-05-09 23:01:41

标签: android android-toolbar badge android-navigation-drawer android-navigationview

我的问题与this question相同(this question的副本)。

该问题的only answer对我来说不起作用,而不是将默认的汉堡图标更改为活动的 标题,它只是为我的活动标题的 正确 添加了一个额外的汉堡包图标。

那我该怎么做呢:

Android hamburger icon with badge counter

我一整天都在四处寻找,但却无处可去。

我发现setNavigationIcon(Drawable drawable)layout方法。理想情况下,我想使用Drawable(包含汉堡图标和徽章视图)而不是{{1}},但我不确定是否/如何实现这一目标 - 或者是否有更好的方法吗?

注意 - 这不是关于如何创建徽章视图的问题。我已经创建了它并在导航菜单项本身上实现了它。所以我现在只需要在默认的汉堡包图标上添加类似的徽章视图。

1 个答案:

答案 0 :(得分:56)

从支持库的24.2.0版开始,ActionBarDrawerToggle的v7版本提供了setDrawerArrowDrawable()方法作为自定义切换图标的方法。 DrawerArrowDrawable是提供该默认图标的类,可以根据需要对其进行子类化以更改它。

例如,BadgeDrawerArrowDrawable类会覆盖draw()方法,以在超类自我绘制后添加基本的红色和白色徽章。这样可以将汉堡包箭头动画保存在下面。

import android.content.Context;
import android.graphics.Color;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.support.v7.graphics.drawable.DrawerArrowDrawable;
import java.util.Objects;

public class BadgeDrawerArrowDrawable extends DrawerArrowDrawable {

    // Fraction of the drawable's intrinsic size we want the badge to be.
    private static final float SIZE_FACTOR = .3f;
    private static final float HALF_SIZE_FACTOR = SIZE_FACTOR / 2;

    private Paint backgroundPaint;
    private Paint textPaint;
    private String text;
    private boolean enabled = true;

    public BadgeDrawerArrowDrawable(Context context) {
        super(context);

        backgroundPaint = new Paint();
        backgroundPaint.setColor(Color.RED);
        backgroundPaint.setAntiAlias(true);

        textPaint = new Paint();
        textPaint.setColor(Color.WHITE);
        textPaint.setAntiAlias(true);
        textPaint.setTypeface(Typeface.DEFAULT_BOLD);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setTextSize(SIZE_FACTOR * getIntrinsicHeight());
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        if (!enabled) {
            return;
        }

        final Rect bounds = getBounds();
        final float x = (1 - HALF_SIZE_FACTOR) * bounds.width();
        final float y = HALF_SIZE_FACTOR * bounds.height();
        canvas.drawCircle(x, y, SIZE_FACTOR * bounds.width(), backgroundPaint);

        if (text == null || text.length() == 0) {
            return;
        }

        final Rect textBounds = new Rect();
        textPaint.getTextBounds(text, 0, text.length(), textBounds);
        canvas.drawText(text, x, y + textBounds.height() / 2, textPaint);
    }

    public void setEnabled(boolean enabled) {
        if (this.enabled != enabled) {
            this.enabled = enabled;
            invalidateSelf();
        }
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setText(String text) {
        if (!Objects.equals(this.text, text)) {
            this.text = text;
            invalidateSelf();
        }
    }

    public String getText() {
        return text;
    }

    public void setBackgroundColor(int color) {
        if (backgroundPaint.getColor() != color) {
            backgroundPaint.setColor(color);
            invalidateSelf();
        }
    }

    public int getBackgroundColor() {
        return backgroundPaint.getColor();
    }

    public void setTextColor(int color) {
        if (textPaint.getColor() != color) {
            textPaint.setColor(color);
            invalidateSelf();
        }
    }

    public int getTextColor() {
        return textPaint.getColor();
    }
}

可以在实例化后的任何时间在切换上设置此实例,并根据需要直接在drawable上设置徽章的属性。

正如下面提到的OP,应使用ContextDrawerArrowDrawable获取用于自定义ActionBar#getThemedContext()的{​​{1}},以确保使用正确的样式值。例如:

Toolbar#getContext()

screenshots

为了简化一些事情,最好同时继承private ActionBarDrawerToggle toggle; private BadgeDrawerArrowDrawable badgeDrawable; ... toggle = new ActionBarDrawerToggle(this, ...); badgeDrawable = new BadgeDrawerArrowDrawable(getSupportActionBar().getThemedContext()); toggle.setDrawerArrowDrawable(badgeDrawable); badgeDrawable.setText("1"); ... ,并通过切换实例处理所有内容。

ActionBarDrawerToggle

有了这个,自动设置自定义徽章drawable,并且可以通过单个对象管理与切换相关的所有内容。

import android.app.Activity; import android.content.Context; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.widget.Toolbar; import java.lang.reflect.Field; import java.lang.reflect.Method; public class BadgeDrawerToggle extends ActionBarDrawerToggle { private BadgeDrawerArrowDrawable badgeDrawable; public BadgeDrawerToggle(Activity activity, DrawerLayout drawerLayout, int openDrawerContentDescRes, int closeDrawerContentDescRes) { super(activity, drawerLayout, openDrawerContentDescRes, closeDrawerContentDescRes); init(activity); } public BadgeDrawerToggle(Activity activity, DrawerLayout drawerLayout, Toolbar toolbar, int openDrawerContentDescRes, int closeDrawerContentDescRes) { super(activity, drawerLayout, toolbar, openDrawerContentDescRes, closeDrawerContentDescRes); init(activity); } private void init(Activity activity) { Context c = getThemedContext(); if (c == null) { c = activity; } badgeDrawable = new BadgeDrawerArrowDrawable(c); setDrawerArrowDrawable(badgeDrawable); } public void setBadgeEnabled(boolean enabled) { badgeDrawable.setEnabled(enabled); } public boolean isBadgeEnabled() { return badgeDrawable.isEnabled(); } public void setBadgeText(String text) { badgeDrawable.setText(text); } public String getBadgeText() { return badgeDrawable.getText(); } public void setBadgeColor(int color) { badgeDrawable.setBackgroundColor(color); } public int getBadgeColor() { return badgeDrawable.getBackgroundColor(); } public void setBadgeTextColor(int color) { badgeDrawable.setTextColor(color); } public int getBadgeTextColor() { return badgeDrawable.getTextColor(); } private Context getThemedContext() { // Don't freak about the reflection. ActionBarDrawerToggle // itself is already using reflection internally. try { Field mActivityImplField = ActionBarDrawerToggle.class .getDeclaredField("mActivityImpl"); mActivityImplField.setAccessible(true); Object mActivityImpl = mActivityImplField.get(this); Method getActionBarThemedContextMethod = mActivityImpl.getClass() .getDeclaredMethod("getActionBarThemedContext"); return (Context) getActionBarThemedContextMethod.invoke(mActivityImpl); } catch (Exception e) { return null; } } } BadgeDrawerToggle的替代品,其构造函数完全相同。

ActionBarDrawerToggle