Android里面原生的控件很多,以前只是会使用,但是现在必须要自己来深入的去了解这种实现过程这个是大神址,http://blog.csdn.net/lmj623565791/article/details/24252901我只是拿来改改添加了抗锯齿。
1.View的过程
想了解view的measure、layout和drawable过程,就要先来了解ViewRoot和DecorView的概念。
view的三大流程就是通过ViewRoot实现的,实质上是viewroot对应的viewrootimpl类,它是连接WindowManager和DecorView的纽带,而DecorView作为页面的顶级容器,一般包括上下两部分,标题栏和内容栏,详情请见下图:
2.下面我们来开始自定义View
第一步:首先自定义属性,xml里面的属性,这一次用一个简单的自定义Textview来展示大概的流程.
首先在res/values新建一个资源文件attr.xml,在里面定义我们的属性.
第二部:写一个Class继承view,重写它的构造器和方法,这里构造器主要是为了取出自定义的属性,然后根据属性对应的id得到xml里面使用属性所得到的值,比如说,字体颜色,字体大小,文本内容等。
package com.example.customview01.view;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.example.customview01.R;
public class CustomTitleView extends View {
/**
* 文本
*/
private String mTitleText;
/**
* 文本的颜色
*/
private int mTitleTextColor;
/**
* 文本的大小
*/
private int mTitleTextSize;
/**
* 绘制时控制文本绘制的范围
*/
private Rect mBound;
private Paint mPaint;
private PaintFlagsDrawFilter pfd;
public CustomTitleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomTitleView(Context context) {
this(context, null);
}
/**
* 获得我自定义的样式属性
*
* @param context
* @param attrs
* @param defStyle
*/
public CustomTitleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
pfd = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
/**
* 获得我们所定义的自定义样式属性
*/
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.CustomTitleView, defStyle, 0);
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.CustomTitleView_titleText:
mTitleText = a.getString(attr);
break;
case R.styleable.CustomTitleView_titleTextColor:
// 默认颜色设置为黑色
mTitleTextColor = a.getColor(attr, Color.BLACK);
break;
case R.styleable.CustomTitleView_titleTextSize:
// 默认设置为16sp,TypeValue也可以把sp转化为px
mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16,
getResources().getDisplayMetrics()));
break;
}
}
//回收TypedArray,以便后面重用。在调用这个函数后,你就不能再使用这个TypedArray
a.recycle();
/**
* 获得绘制文本的宽和高
*/
mPaint = new Paint();
// 抗锯齿
mPaint.setAntiAlias(true);
mPaint.setTextSize(mTitleTextSize);
// mPaint.setColor(mTitleTextColor);
mBound = new Rect();
mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mTitleText = randomText();
//
postInvalidate();
}
});
}
private String randomText() {
Random random = new Random();
Set<Integer> set = new HashSet<Integer>();
while (set.size() < 4) {
int randomInt = random.nextInt(10);
set.add(randomInt);
}
StringBuffer sb = new StringBuffer();
for (Integer i : set) {
sb.append("" + i);
}
return sb.toString();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = 0;
int height = 0;
/**
* 设置宽度
*/
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:// 明确指定了
width = getPaddingLeft() + getPaddingRight() + specSize;
break;
case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
width = getPaddingLeft() + getPaddingRight() + mBound.width();
break;
}
/**
* 设置高度
*/
specMode = MeasureSpec.getMode(heightMeasureSpec);
specSize = MeasureSpec.getSize(heightMeasureSpec);
switch (specMode) {
case MeasureSpec.EXACTLY:// 明确指定了
height = getPaddingTop() + getPaddingBottom() + specSize;
break;
case MeasureSpec.AT_MOST:// 一般为WARP_CONTENT
height = getPaddingTop() + getPaddingBottom() + mBound.height();
break;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
mPaint.setColor(mTitleTextColor);
canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2,
getHeight() / 2 + mBound.height() / 2, mPaint);
// canvas设置抗锯齿
canvas.setDrawFilter(pfd);
}
}
这里面在构造器里面取出字体颜色,字体大小,内容,重写onmeasured方法测量大小,这里要注意MeasureSpace是32位,前两位代表模式,有三种模式:
exactly:父类已经检测出View所需要的精确大小,那么View的具体大小就是SpaceSize,对应着match_parent和具体数值大小
at_most: 父容器制定了一个可用大小即SpaceSize,View的大小不能超出这个值,对应着wrap_content
unspecified:表示一种测量状态,可以跟at_most一起看待。
3.在xml里面引用自定义View,这里要想使用自定义的attr,就要xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"引入,或者xmlns:custom="http://schemas.android.com/apk/res-auto"
好吧,大体流程就是这个样子,最好自己手动敲一下,注意的是这里面怎么确认文字的范围!
1 0