Android自定义View实战-通知红点

2017-02-26 - 2,538 Views - 0 Goods - 2 条评论

前言
今天呢想做一个通知红点。本来想直接用TextView再套个background就好了。可是TextView有很多属性,能用到的只有一小部分,所以索性想自定义个干干净净的View,顺便学习一下自定义View的知识。
由于刚刚入自定义View的坑,做的比较简单...
正文
在values文件夹建立attrs.xml文件,里面写上你需要的属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="myText" format="string" />
    <attr name="myTextColor" format="color" />
    <attr name="myTextSize" format="dimension" />
    <attr name="myBackground" format="color" />
    <attr name="myShape" format="string" />

    <declare-styleable name="NotifyView">
        <attr name="myText" />
        <attr name="myTextColor" />
        <attr name="myTextSize" />
        <attr name="myBackground" />
        <attr name="myShape" />
    </declare-styleable>
</resources>

然后新建一个自定义View继承自View,我这里把它叫做NotifyView
定义NotifyView的成员变量

//view 属性
private String text;
private int textColor;
private float textSize;
private int backgroud;
private String shape;
//定义画笔
private Paint textPaint;
private Paint shapePaint;

private int height;
private int width;

重写构造方法。由于布局文件默认调用的是两个参数的构造方法,但是我们需要用到的是三个参数的构造方法,所以我们要让他调用三个参数的构造方法。构造方法主要用来获取我们自定义的一些属性值

public NotifyView(Context context, AttributeSet attrs){
    this(context, attrs, 0);
}

public NotifyView(Context context){
    this(context, null);
}

public NotifyView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs);
    TypedArray attributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.NotifyView, defStyle, 0);
    int n=attributes.getIndexCount();
    for (int i=0;i<n;i++){ int attribute=attributes.getIndex(i); switch (attribute){ case R.styleable.NotifyView_myText: text=attributes.getString(attribute); if(text.length()>2){
                    text="99+";
                }
                break;
            case R.styleable.NotifyView_myTextColor:
                textColor=attributes.getInt(attribute, R.color.white);
                break;
            case R.styleable.NotifyView_myBackground:
                backgroud=attributes.getInt(attribute,R.color.red);
                break;
            case R.styleable.NotifyView_myShape:
                shape=attributes.getString(attribute);
                break;
            case R.styleable.NotifyView_myTextSize:
                textSize=attributes.getDimension(attribute,12);
                break;
        }
    }
    attributes.recycle();
}

然后绘制形状和文本

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    // 初始化画笔
    textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    shapePaint=new Paint(Paint.ANTI_ALIAS_FLAG);
    height=getHeight();
    width=getWidth();

    //文本属性
    textPaint.setColor(textColor);
    textPaint.setTextAlign(Paint.Align.CENTER);
    textPaint.setTextSize(textSize);
    textPaint.setTypeface(Typeface.DEFAULT_BOLD);
    Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
    float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
    float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
    int baseLineY = (int) (height/2 - top/2 - bottom/2);//基线中间点的y轴计算公式

    shapePaint.setColor(backgroud);
    if("rectangle".equals(shape)) {
        shapePaint.setStyle(Paint.Style.FILL);
        Rect rect=new Rect(height,width,height,width);
        canvas.drawRect(rect, shapePaint);
        canvas.drawText(text,width/2,baseLineY,textPaint);
    }
    //画圆
    else {
        canvas.drawCircle(width / 2, height / 2, Math.min(width, height) / 2, shapePaint);
        canvas.drawText(text,width / 2,baseLineY,textPaint);
    }
}

这里有一点要说明一下,就是文字居中显示的问题
这里借用网上的图来说明一下android canvas drawText()文字居中


安卓绘制文字是相对于基线绘制的,文字的高度即图中top和bottom之间的距离
要让文字水平竖直居中,就要找到图中基线上center那个点的坐标

以矩形为例,矩形中点的坐标为(width/2,height/2);黑点到基线上红点的距离为(-top+bottom)/2-bottom,即-top/2-bottom/2
所以红点的坐标为(width/2,height/2-top/2-bottom/2);

最后就是一些setter和getter方法了


public int getBackgroud() {
    return backgroud;
}

public void setBackgroud(int backgroud) {
    this.backgroud = backgroud;
}

public String getShape() {
    return shape;
}

public void setShape(String shape) {
    this.shape = shape;
}

public String getText() {
    return text;
}

public void setText(String text) {
    if(text.length()>2){
        text="99+";
    }else
        this.text = text;
}

public int getTextColor() {
    return textColor;
}

public void setTextColor(int textColor) {
    this.textColor = textColor;
}

public float getTextSize() {
    return textSize;
}

public void setTextSize(float textSize) {
    this.textSize = textSize;
}

接下来就可以在布局里引用了(要先在布局根标签里引入命名空间xmlns:xesygao="http://schemas.android.com/apk/res-auto")

<com.xesygao.xtieba.custom.NotifyView
	android:layout_width="22dp"
	android:layout_height="22dp"
	android:visibility="gone"
	tools:visibility="visible"
	xesygao:myText="121"
	xesygao:myTextSize="10sp"
	xesygao:myShape="circle"
	xesygao:myBackground="@color/lightRed"
	xesygao:myTextColor="@color/white"
	android:id="@+id/replyme_count"/>

好了,来看看效果

转载请注明原文链接:首页 -> 学习记录 -> Android自定义View实战-通知红点

FuZhou . FuJian

"Never start something you're not willing to finish"