自定义View

来源:互联网 发布:世界杯预选赛积分算法 编辑:程序博客网 时间:2024/06/05 20:20

        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
原创粉丝点击