赞
踩
讲到这里,这个案例基本上快结束了,在绘制(onDraw)方法中,唯一的难点就是文字 基线的确定,这点请大家务必弄清楚。废话不多说,上码!!!
首先,我们先不管基不基线的,先让文字显示出来再说
- package com.example.mytextview;
-
- //import javax.swing.text.View;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.util.AttributeSet;
- import android.view.View;
-
- import androidx.annotation.Nullable;
-
- public class mTextView extends View {
- //1、设置自定义属性变量
- private int mTextSize = 16;
- private int mTextColor = Color.RED;
- private String mText;
-
- //设置文字画笔
- private Paint textPaint;
-
- public mTextView(Context context) {
- this(context,null);
- }
-
- public mTextView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs,0);
- }
-
- public mTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- //2、获取装有自定义属性值的数值
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mTextView);
- //3、精确获取自定义属性值
- mTextSize = typedArray.getDimensionPixelSize(R.styleable.mTextView_mTextSize,mTextSize);//源码用的这个方法,参照 TextView
- mTextColor = typedArray.getColor(R.styleable.mTextView_mTextColor,mTextColor);
- mText = typedArray.getString(R.styleable.mTextView_mText);
- //4、回收 typedArray
- typedArray.recycle();
-
- initData();
- }
-
- private void initData() {
- textPaint = new Paint();
- //抗锯齿
- textPaint.setAntiAlias(true);
- //设置颜色
- textPaint.setColor(mTextColor);
- //设置字体大小
- textPaint.setTextSize(mTextSize);
- }
-
- //5、测量
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- //获取宽高
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
- //获取模式
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- //判断 如果是 wrap_content 模式,则 布局宽高 与 字体大小和字体长度有关
- if(widthMode == MeasureSpec.AT_MOST){
- //设置文字边界
- Rect bounds = new Rect();
- //获取文字边界
- textPaint.getTextBounds(mText,0,mText.length(),bounds);
- //获取边界宽度 === 获取文字宽度
- width = bounds.width();
- }
- if (heightMode == MeasureSpec.AT_MOST){
- //设置文字边界
- Rect bounds = new Rect();
- //获取文字边界
- textPaint.getTextBounds(mText,0,mText.length(),bounds);
- //获取边界高度 === 获取文字高度
- height = bounds.height();
- }
- //最后设置宽高
- setMeasuredDimension(width,height);
- }
-
- //6、绘制
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- //drawText 中存在四个参数分别是: 要显示的文本,基线x方向的起始点,基线y方向的起始点,画笔
- canvas.drawText(mText,0,getHeight(),textPaint);
- }
- }
我们先来运行一遍,看看效果:
显示不全的原因是我们把宽高写死了,把布局文件里 控件的宽高改成 wrap_content 即可:
下面显示不全,这就有关基线问题了,那我们先来看看什么是基线,怎么求,见图:
所以我们可以这样求基线,代码里有注释,如下:
- package com.example.mytextview;
-
- //import javax.swing.text.View;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.util.AttributeSet;
- import android.view.View;
-
- import androidx.annotation.Nullable;
-
- public class mTextView extends View {
- //1、设置自定义属性变量
- private int mTextSize = 16;
- private int mTextColor = Color.RED;
- private String mText;
-
- //设置文字画笔
- private Paint textPaint;
-
- public mTextView(Context context) {
- this(context,null);
- }
-
- public mTextView(Context context, @Nullable AttributeSet attrs) {
- this(context, attrs,0);
- }
-
- public mTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
-
- //2、获取装有自定义属性值的数值
- TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mTextView);
- //3、精确获取自定义属性值
- mTextSize = typedArray.getDimensionPixelSize(R.styleable.mTextView_mTextSize,mTextSize);//源码用的这个方法,参照 TextView
- mTextColor = typedArray.getColor(R.styleable.mTextView_mTextColor,mTextColor);
- mText = typedArray.getString(R.styleable.mTextView_mText);
- //4、回收 typedArray
- typedArray.recycle();
-
- initData();
- }
-
- private void initData() {
- textPaint = new Paint();
- //抗锯齿
- textPaint.setAntiAlias(true);
- //设置颜色
- textPaint.setColor(mTextColor);
- //设置字体大小
- textPaint.setTextSize(mTextSize);
- }
-
- //5、测量
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- //获取宽高
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
- //获取模式
- int widthMode = MeasureSpec.getMode(widthMeasureSpec);
- int heightMode = MeasureSpec.getMode(heightMeasureSpec);
- //判断 如果是 wrap_content 模式,则 布局宽高 与 字体大小和字体长度有关
- if(widthMode == MeasureSpec.AT_MOST){
- //设置文字边界
- Rect bounds = new Rect();
- //获取文字边界
- textPaint.getTextBounds(mText,0,mText.length(),bounds);
- //获取边界宽度 === 获取文字宽度
- width = bounds.width();
- }
- if (heightMode == MeasureSpec.AT_MOST){
- //设置文字边界
- Rect bounds = new Rect();
- //获取文字边界
- textPaint.getTextBounds(mText,0,mText.length(),bounds);
- //获取边界高度 === 获取文字高度
- height = bounds.height();
- }
- //最后设置宽高
- setMeasuredDimension(width,height);
- }
-
- //6、绘制
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- //drawText 中存在四个参数分别是: 要显示的文本,基线x方向的起始点,基线y方向的起始点,画笔
- Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
- //botto 为正值 top 为负值(看图中画的坐标系)
- int dy = (fontMetricsInt.bottom - fontMetricsInt.top)/2 - fontMetricsInt.bottom;
- int baseLine = getHeight()/2 + dy;
- canvas.drawText(mText,0,baseLine,textPaint);
- }
- }
我们再来运行一把,看看效果:
可见,我们成功了,这篇到此为止,下一篇我们将一些优化。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。