先上图
未读消息View介绍
1.可根据文本长度动态改变view的宽度,数字10以下的显示为圆形,10以上的显示为上述效果
2.使用方便,引用到xml中后,直接显示高度即可,即可根据高度自动生成最佳显示效果
3.直接在代码中调用setText()即可
分析
其实完成这样的效果还是很简单的,主要我是通过画一个圆角矩形来实现这样的效果,圆角矩形很轻松就能实现这两种效果的切换,至于怎样子写,之后会有介绍。
关于自适应宽度的实现,我只要是通过重写onMeasure方法,对其进行拦截。
开始实现
实现步骤其实很简单,因为功能上不是很多,对于我现在的需求,只要能显示未读数量并做好适配就好了。所以只要写好onMeasure和onDraw就好了,方法很简单。因为本人实力有限,实现起来肯定还是使用很简单的方法的。
现在我们先看onMeasure,这里主要是是为了做好实现自适应宽度
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取控件高度
height = MeasureSpec.getSize(heightMeasureSpec);
//定义字体大小,自测了一下,与高度相差6dp的字体大小看着还是挺舒服的
textSize = height - getResources().getDimensionPixelSize(R.dimen.dp6);
textPaint.setTextSize(textSize);
//获取文本宽度
int textWidth = (int) textPaint.measureText(text);
//区分画圆的是圆形还是圆角矩形
if (text.length() > 1) {
roundWidth = textWidth + height - textWidth / text.length();
} else {
roundWidth = height;
}
//重新测量控件
setMeasuredDimension(roundWidth, height);
}
上述方法还是很简单的也标号注释了,不用一句句来讲了。
roundWidth = textWidth + height - textWidth / text.length();
实现上述效果的核心就是这段代码,我想应该看得懂的。逻辑不是很强。
现在我们再看onDraw,也是最后一步画矩形与画字
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画矩形
canvas.setDrawFilter(paintFlagsDrawFilter);
roundRectF.set(0, 0, roundWidth, height);
canvas.drawRoundRect(roundRectF, height / 2, height / 2, roundRectPaint);
//画字
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;
int baseLintY = (int) (roundRectF.centerY() - top / 2 - bottom / 2);
canvas.drawText(text, roundRectF.centerX(), baseLintY, textPaint);
}
对于画矩形和画字不是这篇的重点,不懂的可以自己百度一下,我也是百度慢慢学起来的。主要是画字需要居中,关键在于
int baseLintY = (int) (roundRectF.centerY() - top / 2 - bottom / 2);
这边代码,获取字体的基线,来实现居中效果。
最后上所有代码,不是很难,代码量也不多,很容易懂
package com.demo.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.demo.R;
public class MyTextView extends View {
private Paint roundRectPaint;
private RectF roundRectF;
private int height;
private int roundWidth;
private Paint textPaint;
private float textSize;
private String text;
private PaintFlagsDrawFilter paintFlagsDrawFilter;
public MyTextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
text = "2";
roundRectPaint = new Paint();
roundRectPaint.setStyle(Paint.Style.FILL);
roundRectPaint.setAntiAlias(true);
roundRectPaint.setColor(Color.RED);
roundRectF = new RectF();
//设置字体为粗体
textPaint = new Paint(Paint.LINEAR_TEXT_FLAG);
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textPaint.setTextAlign(Paint.Align.CENTER);
//实现抗锯齿
paintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取控件高度
height = MeasureSpec.getSize(heightMeasureSpec);
//定义字体大小,自测了一下,与高度相差6dp的字体大小看着还是挺舒服的
textSize = height - getResources().getDimensionPixelSize(R.dimen.dp6);
textPaint.setTextSize(textSize);
//获取文本宽度
int textWidth = (int) textPaint.measureText(text);
//区分画圆的是圆形还是圆角矩形
if (text.length() > 1) {
roundWidth = textWidth + height - textWidth / text.length();
} else {
roundWidth = height;
}
//重新测量控件
setMeasuredDimension(roundWidth, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//画矩形
canvas.setDrawFilter(paintFlagsDrawFilter);
roundRectF.set(0, 0, roundWidth, height);
canvas.drawRoundRect(roundRectF, height / 2, height / 2, roundRectPaint);
//画字
Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
float top = fontMetrics.top;
float bottom = fontMetrics.bottom;
int baseLintY = (int) (roundRectF.centerY() - top / 2 - bottom / 2);
canvas.drawText(text, roundRectF.centerX(), baseLintY, textPaint);
}
public void setText(String text) {
this.text = text;
//重走onMeasure
requestLayout();
}
}
代码真的很少,看不懂的查一下也很快能看懂的。
最后在xml中
<com.demo.view.MyTextView
android:layout_marginTop="20dp"
android:layout_marginLeft="20dp"
android:layout_width="wrap_content"
android:layout_height="30dp"/>
好了,就这样结束了,这里android:layout_width不管设什么值都是自适应的,因为在onMeasure中直接定死了。若要区分开来,可重写onMeasure做判断。
网友评论
比如动态设置字体大小、颜色、背景的颜色、形状等。
谢谢!