自定义View之消息数量提示View-TipView

一、功能 效果图

一个View就像实现,支持设置 背景色、数量文字、文字颜色、文字大小、最大文字、只显示圆点,自动适配文字大小,不会超出圆圈的范围

Android 消息数角标 安卓图标显示消息数量_android

二、实现原理

画一个圆,然后再画文本。

三、代码

1. 在value文件夹下的attrs创建对应的自定义属性
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="TipView">
        <!-- 显示的数量 -->
        <attr name="text" format="integer"/>
        <!-- 文字大小,0-1,1为默认,值越小,文字越小 -->
        <attr name="textMargin" format="float"/>
        <!-- 数量文字的颜色 -->
        <attr name="textColor" format="reference|color"/>
        <!-- 最大数量,超出这个数字会显示 这个数字+ -->
        <attr name="textMax" format="integer"/>
        <!-- 背景圆的颜色 -->
        <attr name="circleColor" format="reference|color"/>
    </declare-styleable>
</resources>
2.TipView代码

注释已经写上去了

package com.tpnet.easynavigationbar.EasyNavigation;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import com.tpnet.easynavigationbar.R;

/**
 * Created by LITP on 2016/9/9.
 */
public class TipView extends View {

    private int textColor = Color.WHITE;   //默认
    private float textMargin = 0.9f;    //文字边距,0-1 ,越小字越小
    private int circleColor = Color.RED;  //默认背景颜色
    private int text = 0;               //默认文本0,0就是不显示
    private int textMax = 99 ;          //最大数值,超出就显示 +

    Paint paint = new Paint();   //尽量不要在onDraw创建对象,因为onDraw经常调用

    public TipView(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TipView);

        // 获取自定义属性的文字
        int text = ta.getInt(R.styleable.TipView_text, -1);
        setText(text);

        // 获取自定义属性的 最大消息数
        int textMax = ta.getInt(R.styleable.TipView_textMax, 0);
        setTextMax(textMax);

        // 获取自定义属性的字体颜色,默认为白色
        int textColor = ta.getColor(R.styleable.TipView_textColor, 0);
        setTextColor(textColor);

        // 获取自定义属性的字体距离圆的距离,默认为5px
        Float textMargin = ta.getFloat(R.styleable.TipView_textMargin,0);
        setTextMargin(textMargin);

        // 获取自定义属性的原型背景颜色,默认为红色
        int circleColor = ta.getColor(R.styleable.TipView_circleColor, 0);
        setCircleColor(circleColor);

        ta.recycle();

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int mWidthHalf = getMeasuredWidth() / 2;

        //创建画笔
        paint.setAntiAlias(true);  // 设置画笔的锯齿效果。true是去除锯齿,更平滑

        paint.setColor(circleColor);// 设置圆的背景红色
        //cx:圆心的x坐标。cy:圆心的y坐标。radius:圆的半径。paint:绘制时所使用的画笔
        canvas.drawCircle(mWidthHalf, mWidthHalf, mWidthHalf, paint);

        //写文字,为0 就不显示
        if( text  != 0){
            paint.setColor(textColor);
            paint.setTextSize(getTextSize());

            paint.setTextAlign(Paint.Align.CENTER);   //对齐原点位置

            //text:要绘制的文字,x:绘制原点x坐标  0y:绘制原点y坐标  底部基线的位置,paint:用来做画的画笔
            canvas.drawText(text > textMax ? textMax+"+" : String.valueOf(text),
                    mWidthHalf,
                    getTextY(paint),    //文本基线
                    paint);
        }

    }

    /**
     * 每位数大小不一样,防止超出圆圈
     * @return 字体size
     */
    private Float getTextSize(){
        float num ;
        if(text >= 100){  //三位数
            num = 0.5f;
        }else if(text >= 10){ //两位数
            num = 0.7f;
        }else{
            num = 0.9f;
        }
        return getMeasuredHeight() * num * textMargin;

    }



    private int getTextY(Paint paint){
        Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
        return ((getMeasuredHeight() - fontMetrics.bottom - fontMetrics.top) / 2);
    }




    public int getTextMax() {
        return textMax;
    }

    public void setTextMax(int textMax) {
        if(textMax > 0){
            this.textMax = textMax;
        }

    }

    public int getText() {
        return text;
    }

    public void setText(int text) {
        if (text < 0) {
            setVisibility(GONE);
        }else{
            this.text = text;
        }
        invalidate();
    }

    public int getTextColor() {
        return textColor;
    }


    public void setTextColor(int textColor) {
        if (textColor != 0) {
            this.textColor = textColor;
            invalidate();
        }
    }

    public float getTextMargin() {
        return textMargin;
    }

    public void setTextMargin(float textMargin) {
        if(textMargin > 1){   //最大为1
            this.textMargin = 1;
        }else if(textMargin < 0){
            this.textMargin = 0;
        }else if(textMargin != 0){
            this.textMargin = textMargin;
        }

    }

    public int getCircleColor() {
        return circleColor;
    }

    public void setCircleColor(int circleColor) {
        if (circleColor != 0) {
            this.circleColor = circleColor;
            invalidate();
        }
    }


}

3.使用

在布局使用控件即可,可以添加自定义属性,也能在代码设置。如果是红底白字,就默认呢就行了,不用加自定义属性

不添加自定义属性,默认

<com.tpnet.easynavigationbar.EasyNavigation.TipView
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="3dp"
        />

添加自定义属性

<com.tpnet.easynavigationbar.EasyNavigation.TipView
        android:layout_width="18dp"
        android:layout_height="18dp"
        android:layout_alignParentRight="true"
        android:layout_marginRight="10dp"
        android:layout_marginTop="3dp"
        app:text="1"
        app:textColor="@android:color/white"
        app:textMargin="0.7"
        app:textMax="99"
        app:circleColor="@android:color/holo_red_light"
        />