前言
今天呢想做一个通知红点。本来想直接用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"/>