android 自定义View

网上有很多关于关于自定义view 的文章,这里我还是自己动手谢了一下自定义view,来熟悉自定义view 的主要步骤。总计如下几点

  • 声明自定义的属性。
  • 获取自定义view 的属性value。
  • onMesure 获取自定义view 的大小
  • onLayout 确定自定义view 的位置
  • onDraw 使用Canvas 画出自定义view

我们通过自定义一个CustomTextview 来了解一下相关的过程。

代码参见 * https://github.com/lijing01/AndroidDemo

声明自定义View 的属性

在values 下面创建一个attrs 属性文件。







上面一共定义了四个属性,text, textColor,textBgColor,textSize 。format 指的是 attr 的类型,具体可以参考一下这篇文章Android中attr自定义属性详解 。

获取自定义属性的 value


TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTextView, defStyleAttr, 0);
for (int i = 0; i < a.getIndexCount(); i++) {
int arrt = a.getIndex(i);
switch (arrt) {
case R.styleable.CustomTextView_ttext:
text = a.getString(arrt);
break;
case R.styleable.CustomTextView_ttextColor:
textColor = a.getColor(arrt, Color.BLACK);
break;
case R.styleable.CustomTextView_ttextBgColor:
textBgColor = a.getColor(arrt, Color.BLUE);
break;
case R.styleable.CustomTextView_ttextSize:
textSize = a.getDimensionPixelSize(arrt,(int)
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
16,getResources().getDisplayMetrics()));
break;
}
}
if(textSize == 0){
textSize=(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics());
}
a.recycle();
mPaint= newPaint();
mPaint.setTextSize(textSize);
mPaint.setColor(textColor);
mRect = new Rect();
mPaint.getTextBounds(text, 0, text.length(), mRect);

如上我们获取到了自定义的属性值。当textSize 没有赋值的时候我们会给textSize 赋默认值,以免在真实绘制的过程中size 为 0。 获取完,自定义属性 调用 a.recycle(); 防止内存溢出。

绘制过程


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width;
int height;
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
mPaint.setTextSize(textSize);
mPaint.getTextBounds(text, 0, text.length(), mRect);
float textWidth = mRect.width();
int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
width = desired;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
mPaint.setTextSize(textSize);
mPaint.getTextBounds(text, 0, text.length(), mRect);
float textHeight = mRect.height();
int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
height = desired;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(textBgColor);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
mPaint.setColor(textColor);
canvas.drawText(text, (getWidth()- mRect.width()) / 2, (getHeight() +
mRect.height()) / 2, mPaint);
}

刚开始的时候遇到一个坑,没有重现 onmesure 方法,带来的后果是 layout_width, layout_height, 无论是设置成 match_parent, 还是 warp_content, 的结果都是match_parent。 重写之后一切正常。效果如下图。

android 自定义View_第1张图片
Paste_Image.png

OnLayout
因为我们现在讨论的是View,没有子View需要排列,所以这一步其实我们不需要做额外的工作。插一句,对ViewGroup类,onLayout方法中,我们需要将所有子View的大小宽高设置好,这个我们下一篇会详细说。

View中还有三个比较重要的方法

  • requestLayout
    View重新调用一次layout过程。
  • invalidate
    View重新调用一次draw过程
  • forceLayout
    标识View在下一次重绘,需要重新调用layout过程。

自定义view 相关文章
android 自定义ViewGroup

Reffer

  • http://blog.csdn.net/lmj623565791/article/details/24252901
  • http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0606/3001.html
  • http://www.jianshu.com/p/84cee705b0d3
  • android 坐标详解

你可能感兴趣的:(android 自定义View)