[关闭]
@linux1s1s 2016-09-22T11:04:35.000000Z 字数 3817 阅读 2169

Android 自定义简单View

AndroidView


阅读此篇博客前请先行阅读 Android View 自定义属性 然后我们来回顾一下自定义View需要做哪些事情:

上面四个步骤一般在自定义View的时候都需要,如果父类的onMeasure测量有误,这里一般会发生在wrap_content的时候,父类的测量有可能会当成match_parent来处理,所以需要我们主动修改这个测量过程。

1. 自定义View属性【attrs】

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <attr name="titleText" format="string" />
  4. <attr name="titleColor" format="color" />
  5. <attr name="titleSize" format="dimension" />
  6. <declare-styleable name="TitleView">
  7. <attr name="titleText" />
  8. <attr name="titleColor" />
  9. <attr name="titleSize" />
  10. </declare-styleable>
  11. </resources>

这里提示一下,format的类型一共有以下几个:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;

然后我们在Layout文件中使用这个自定义属性

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:linroid="http://schemas.android.com/apk/res-auto"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent">
  5. <android.neulion.com.viewattrs.TitleView
  6. android:layout_width="match_parent"
  7. android:layout_height="@dimen/custom_view_height"
  8. android:id="@+id/my_id"
  9. linroid:titleText="@string/hello_world"
  10. linroid:titleSize="@dimen/title_text_size"
  11. linroid:titleColor="@android:color/background_dark" />
  12. </RelativeLayout>

注意这里的命名空间,Studio下可能会报错,但是并不影响使用。

2. 自定义View类

  1. public class TitleView extends View
  2. {
  3. private String mTitleText;
  4. private int mTitleColor;
  5. private int mTitleSize;
  6. private final Paint mPaint;
  7. private final Rect mRect;
  8. public TitleView(Context context, AttributeSet attrs)
  9. {
  10. this(context, attrs, 0);
  11. }
  12. public TitleView(Context context, AttributeSet attrs, int defStyleAttr)
  13. {
  14. super(context, attrs, defStyleAttr);
  15. final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TitleView);
  16. //one way
  17. // mTitleText = a.getString(R.styleable.TitleView_titleText);
  18. // mTitleColor = a.getInt(R.styleable.TitleView_titleColor, -1);
  19. // mTitleSize = a.getInt(R.styleable.TitleView_titleSize, -1);
  20. //or other way
  21. final int size = a.getIndexCount();
  22. for (int i = 0; i < size; i++)
  23. {
  24. int attr = a.getIndex(i);
  25. switch (attr)
  26. {
  27. case R.styleable.TitleView_titleText:
  28. mTitleText = a.getString(attr);
  29. break;
  30. case R.styleable.TitleView_titleColor:
  31. mTitleColor = a.getDimensionPixelSize(attr, -1);
  32. break;
  33. case R.styleable.TitleView_titleSize:
  34. mTitleSize = a.getColor(attr, -1);
  35. break;
  36. }
  37. }
  38. a.recycle();
  39. mPaint = new Paint();
  40. mPaint.setTextSize(mTitleSize);
  41. mRect = new Rect();
  42. mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mRect);
  43. }
  44. ...
  45. }

3. 重写onMeasure方法

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  3. {
  4. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  5. }

4. 重写onDraw方法

  1. @Override
  2. protected void onDraw(Canvas canvas)
  3. {
  4. super.onDraw(canvas);
  5. mPaint.setColor(Color.YELLOW);
  6. canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
  7. mPaint.setColor(mTitleColor);
  8. canvas.drawText(mTitleText,
  9. getWidth() / 2 - mRect.width() / 2, getHeight() / 2 - mRect.height() / 2, mPaint);
  10. }

Run一下,看看效果如下:

此处输入图片的描述

看到这里是不是感觉良好,不过,加入我们把layout文件修改成wrap_content这个时候是啥样子?

此处输入图片的描述

完全不是我们想象的样子了,说明父View的measure出问题了,它并没有测量准确我们希望的样子,所以必须自己重写onMeasure方法

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  3. {
  4. int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  5. int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  6. int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  7. int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  8. int width;
  9. int height ;
  10. if (widthMode == MeasureSpec.EXACTLY)
  11. {
  12. width = widthSize;
  13. } else
  14. {
  15. mPaint.setTextSize(mTitleTextSize);
  16. mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);
  17. float textWidth = mBounds.width();
  18. int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
  19. width = desired;
  20. }
  21. if (heightMode == MeasureSpec.EXACTLY)
  22. {
  23. height = heightSize;
  24. } else
  25. {
  26. mPaint.setTextSize(mTitleTextSize);
  27. mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);
  28. float textHeight = mBounds.height();
  29. int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
  30. height = desired;
  31. }
  32. setMeasuredDimension(width, height);
  33. }

接下来在Run一下看看

此处输入图片的描述

到这里已经自定义View完成了,是不是没有想象中的那么难(^o^)/~。

此篇博客编辑自CSDN-HongYang的博客,在此向该大牛致敬

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注