当前位置:   article > 正文

Android自定义控件(四)---实战篇(详解onDraw)_android ondraw

android ondraw

讲到这里,这个案例基本上快结束了,在绘制(onDraw)方法中,唯一的难点就是文字 基线的确定,这点请大家务必弄清楚。废话不多说,上码!!!

首先,我们先不管基不基线的,先让文字显示出来再说

  1. package com.example.mytextview;
  2. //import javax.swing.text.View;
  3. import android.content.Context;
  4. import android.content.res.TypedArray;
  5. import android.graphics.Canvas;
  6. import android.graphics.Color;
  7. import android.graphics.Paint;
  8. import android.graphics.Rect;
  9. import android.util.AttributeSet;
  10. import android.view.View;
  11. import androidx.annotation.Nullable;
  12. public class mTextView extends View {
  13. //1、设置自定义属性变量
  14. private int mTextSize = 16;
  15. private int mTextColor = Color.RED;
  16. private String mText;
  17. //设置文字画笔
  18. private Paint textPaint;
  19. public mTextView(Context context) {
  20. this(context,null);
  21. }
  22. public mTextView(Context context, @Nullable AttributeSet attrs) {
  23. this(context, attrs,0);
  24. }
  25. public mTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  26. super(context, attrs, defStyleAttr);
  27. //2、获取装有自定义属性值的数值
  28. TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mTextView);
  29. //3、精确获取自定义属性值
  30. mTextSize = typedArray.getDimensionPixelSize(R.styleable.mTextView_mTextSize,mTextSize);//源码用的这个方法,参照 TextView
  31. mTextColor = typedArray.getColor(R.styleable.mTextView_mTextColor,mTextColor);
  32. mText = typedArray.getString(R.styleable.mTextView_mText);
  33. //4、回收 typedArray
  34. typedArray.recycle();
  35. initData();
  36. }
  37. private void initData() {
  38. textPaint = new Paint();
  39. //抗锯齿
  40. textPaint.setAntiAlias(true);
  41. //设置颜色
  42. textPaint.setColor(mTextColor);
  43. //设置字体大小
  44. textPaint.setTextSize(mTextSize);
  45. }
  46. //5、测量
  47. @Override
  48. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  49. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  50. //获取宽高
  51. int width = MeasureSpec.getSize(widthMeasureSpec);
  52. int height = MeasureSpec.getSize(heightMeasureSpec);
  53. //获取模式
  54. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  55. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  56. //判断 如果是 wrap_content 模式,则 布局宽高 与 字体大小和字体长度有关
  57. if(widthMode == MeasureSpec.AT_MOST){
  58. //设置文字边界
  59. Rect bounds = new Rect();
  60. //获取文字边界
  61. textPaint.getTextBounds(mText,0,mText.length(),bounds);
  62. //获取边界宽度 === 获取文字宽度
  63. width = bounds.width();
  64. }
  65. if (heightMode == MeasureSpec.AT_MOST){
  66. //设置文字边界
  67. Rect bounds = new Rect();
  68. //获取文字边界
  69. textPaint.getTextBounds(mText,0,mText.length(),bounds);
  70. //获取边界高度 === 获取文字高度
  71. height = bounds.height();
  72. }
  73. //最后设置宽高
  74. setMeasuredDimension(width,height);
  75. }
  76. //6、绘制
  77. @Override
  78. protected void onDraw(Canvas canvas) {
  79. super.onDraw(canvas);
  80. //drawText 中存在四个参数分别是: 要显示的文本,基线x方向的起始点,基线y方向的起始点,画笔
  81. canvas.drawText(mText,0,getHeight(),textPaint);
  82. }
  83. }

我们先来运行一遍,看看效果:

显示不全的原因是我们把宽高写死了,把布局文件里 控件的宽高改成 wrap_content 即可:

 下面显示不全,这就有关基线问题了,那我们先来看看什么是基线,怎么求,见图:

所以我们可以这样求基线,代码里有注释,如下:

  1. package com.example.mytextview;
  2. //import javax.swing.text.View;
  3. import android.content.Context;
  4. import android.content.res.TypedArray;
  5. import android.graphics.Canvas;
  6. import android.graphics.Color;
  7. import android.graphics.Paint;
  8. import android.graphics.Rect;
  9. import android.util.AttributeSet;
  10. import android.view.View;
  11. import androidx.annotation.Nullable;
  12. public class mTextView extends View {
  13. //1、设置自定义属性变量
  14. private int mTextSize = 16;
  15. private int mTextColor = Color.RED;
  16. private String mText;
  17. //设置文字画笔
  18. private Paint textPaint;
  19. public mTextView(Context context) {
  20. this(context,null);
  21. }
  22. public mTextView(Context context, @Nullable AttributeSet attrs) {
  23. this(context, attrs,0);
  24. }
  25. public mTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
  26. super(context, attrs, defStyleAttr);
  27. //2、获取装有自定义属性值的数值
  28. TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mTextView);
  29. //3、精确获取自定义属性值
  30. mTextSize = typedArray.getDimensionPixelSize(R.styleable.mTextView_mTextSize,mTextSize);//源码用的这个方法,参照 TextView
  31. mTextColor = typedArray.getColor(R.styleable.mTextView_mTextColor,mTextColor);
  32. mText = typedArray.getString(R.styleable.mTextView_mText);
  33. //4、回收 typedArray
  34. typedArray.recycle();
  35. initData();
  36. }
  37. private void initData() {
  38. textPaint = new Paint();
  39. //抗锯齿
  40. textPaint.setAntiAlias(true);
  41. //设置颜色
  42. textPaint.setColor(mTextColor);
  43. //设置字体大小
  44. textPaint.setTextSize(mTextSize);
  45. }
  46. //5、测量
  47. @Override
  48. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  49. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  50. //获取宽高
  51. int width = MeasureSpec.getSize(widthMeasureSpec);
  52. int height = MeasureSpec.getSize(heightMeasureSpec);
  53. //获取模式
  54. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  55. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  56. //判断 如果是 wrap_content 模式,则 布局宽高 与 字体大小和字体长度有关
  57. if(widthMode == MeasureSpec.AT_MOST){
  58. //设置文字边界
  59. Rect bounds = new Rect();
  60. //获取文字边界
  61. textPaint.getTextBounds(mText,0,mText.length(),bounds);
  62. //获取边界宽度 === 获取文字宽度
  63. width = bounds.width();
  64. }
  65. if (heightMode == MeasureSpec.AT_MOST){
  66. //设置文字边界
  67. Rect bounds = new Rect();
  68. //获取文字边界
  69. textPaint.getTextBounds(mText,0,mText.length(),bounds);
  70. //获取边界高度 === 获取文字高度
  71. height = bounds.height();
  72. }
  73. //最后设置宽高
  74. setMeasuredDimension(width,height);
  75. }
  76. //6、绘制
  77. @Override
  78. protected void onDraw(Canvas canvas) {
  79. super.onDraw(canvas);
  80. //drawText 中存在四个参数分别是: 要显示的文本,基线x方向的起始点,基线y方向的起始点,画笔
  81. Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
  82. //botto 为正值 top 为负值(看图中画的坐标系)
  83. int dy = (fontMetricsInt.bottom - fontMetricsInt.top)/2 - fontMetricsInt.bottom;
  84. int baseLine = getHeight()/2 + dy;
  85. canvas.drawText(mText,0,baseLine,textPaint);
  86. }
  87. }

我们再来运行一把,看看效果:

可见,我们成功了,这篇到此为止,下一篇我们将一些优化。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/673362
推荐阅读
相关标签
  

闽ICP备14008679号