一、概述
以前在项目当中很多效果要实现,首先想到的就是去网上找,想自己写又不太懂原理,网上看了几篇文章或者专题都是专门分析源码或者讲解方法的,没有结合项目,对知识是学了又忘。跟着Darren大神学了下,感觉不错。他山之石,可以攻玉。现在记录学习的过程,理清下思路,顺便也可以方便别人。今天要讲的是自己绘制TextView熟悉下自定义view一般的操作流程。
二、效果图
三、思路分析
3.1写自定义属性,attrs文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TextView">
<attr name="lctyText" format="string"></attr>
<attr name="lctyColor" format="color"></attr>
<attr name="lctySize" format="dimension"></attr>
</declare-styleable>
</resources>
name表示属性名,format表示属性格式,这里自定义了三个属性,文本内容,文本颜色,文本尺寸。
3.2写自定义TextView,继承自view,在构造函数中拿出属性,初始化画笔
private int mTextSize = 15;
private int mTextColor = Color.BLACK;
private String mText; //文本
Paint mPaint;
public TextView(Context context) {
this(context,null);
}
public TextView(Context context, AttributeSet attrs) {
this(context,attrs,0);
}
//构造函数里拿到自定义属性 初始化画笔
public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.TextView);
mText = a.getString(R.styleable.TextView_lctyText);
mTextColor = a.getColor(R.styleable.TextView_lctyColor,mTextColor);
mTextSize = a.getDimensionPixelSize(R.styleable.TextView_lctySize,sp2px(mTextSize));
a.recycle();
mPaint = new Paint();
//抗锯齿
mPaint.setAntiAlias(true);
//文字大小
mPaint.setTextSize(mTextSize);
//文字颜色
mPaint.setColor(mTextColor);
}
//sp单位转为px
private int sp2px(int size) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,size,getResources().getDisplayMetrics());
}
3.3复写onMeasure方法,获取测绘模式,进行判断,计算宽高。
//onMeasure方法测绘 设置宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//得到测量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//得到宽高的值
int height = MeasureSpec.getSize(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
//判断测量模式
//如果mode是EXACTLY(match_parent 100dp) 不用管 直接用户是设置多少就是多少
//如果mode是AT_MOST(wrap_content) 要判断设置宽高
if (widthMode == MeasureSpec.AT_MOST){
//用画笔测量文字的宽高 由字体大小和宽高决定
Rect bunds = new Rect();
//得到文字的矩形区域
mPaint.getTextBounds(mText,0,mText.length(),bunds);
width = getPaddingRight()+ getPaddingLeft() + bunds.width(); //左右间距加上文本宽度
}
if (heightMode == MeasureSpec.AT_MOST){
//用画笔测量文字的宽高 由字体大小和宽高决定
Rect bunds = new Rect();
//得到文字的矩形区域
mPaint.getTextBounds(mText,0,mText.length(),bunds);
height = getPaddingBottom()+getPaddingTop()+bunds.height(); //上下间距加上文本高度
}
//设置宽高
setMeasuredDimension(width,height);
}
3.4在ondraw()方法中调用画笔的drawText方法进行绘制
//onDraw()方法进行文字绘制
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint)
/* The text to be drawn 要绘制的文字
* The x-coordinate of the origin of the text being drawn 绘制的起始点
* The y-coordinate of the baseline of the text being drawn 绘制的基线
* The paint used for the text (e.g. color, size, style) 画笔
* dy是整个文字的高度的一般和基线之间的增量
*/
Paint.FontMetricsInt metricsInt = mPaint.getFontMetricsInt();
int dy = (metricsInt.bottom - metricsInt.top)/2 - metricsInt.bottom;
int baseline = getHeight()/2 + dy;
canvas.drawText(mText,getPaddingLeft(),baseline,mPaint);
}
四、FontMetrics的理解
Paint.FontMetrics和Paint.FontMetricsInt这两个方法是一样的,只是后者取到的值是一个整形。
top:最高字符到baseline的距离,即ascent的最大值 ascent:字符最高处的距离到baseline的值 descent:下划线到字符最低处的距离 bottom:下划线到最低字符的距离,即descent的最大值 leading:上一行字符的descent到下一行的ascent之间的距离
可以对照着这个图理解:
那么baseLine的计算应该就是,整行字符的高度+增量y,增量的计算公式为:
y=(metricsInt.bottom - metricsInt.top)/2 - metricsInt.bottom
分析完毕,源码地址:http://pan.baidu.com/s/1nuRJYI1
网友评论