Add button with a counter into the toolbar

2020-03-31 06:34发布

My ToolBar

enter image description here

How can I make counter under the cart?

enter image description here

3条回答
够拽才男人
2楼-- · 2020-03-31 07:16

This should be the approach to achieve this

  • Create a BadgeDrawable class that draws a count of notification plus an eye-popping red background circle (like in the screenshot ).
  • Define a LayerDrawable in XML to set as the android:icon of our MenuItem. The bottom layer of the LayerDrawable is the MenuItem's icon (typically a .png), and the top layer is the BadgeDrawable.
  • Simulate querying the count of notifications in our Activity, update the BadgeDrawable's count, then call Activity#invalidateOptionsMenu() to force the ActionBar Menu to refresh.

Output will be

enter image description here

BadgeDrawable.java

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

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

For /res/drawable/ic_menu_notifications.xml

<?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/ic_action_email"
        android:gravity="center" />

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

/res/menu/menu_home.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/action_notifications"
        android:title="Notifications"
        android:icon="@drawable/ic_menu_notifications"
        android:showAsAction="always"/>
</menu>

Now in the HomeActivity.java

public class HomeActivity extends Activity {

    private int mNotificationsCount = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        // Run a task to fetch the notifications count
        new FetchCountTask().execute();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.home, menu);

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

        // Update LayerDrawable's BadgeDrawable
        Utils.setBadgeCount(this, icon, mNotificationsCount);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == R.id.action_notifications) {
            // TODO: display unread notifications.
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /*
    Updates the count of notifications in the ActionBar.
     */
    private void updateNotificationsBadge(int count) {
        mNotificationsCount = count;

        // force the ActionBar to relayout its MenuItems.
        // onCreateOptionsMenu(Menu) will be called again.
        invalidateOptionsMenu(); 
    }

    /*
    Sample AsyncTask to fetch the notifications count
    */
    class FetchCountTask extends AsyncTask<Void, Void, Integer> {

        @Override
        protected Integer doInBackground(Void... params) {
            // example count. This is where you'd 
            // query your data store for the actual count.
            return 5; 
        }

        @Override
        public void onPostExecute(Integer count) {
            updateNotificationsBadge(count);
        }
    }
}

Utility class Utils.java

public class Utils {

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

Reference Link for Full Code

查看更多
Summer. ? 凉城
4楼-- · 2020-03-31 07:34

You have to create a custom drawable for that (I let you find how to create one the way you want it). Lets call it myDrawable. Then in your menu xml file you reference it with:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/myMenuId"
        android:icon="@drawable/myDrawable"
        android:showAsAction="always" />

</menu>
查看更多
登录 后发表回答