自定义view的概括在自定义view(一)之概述中已经讲过,不清楚的朋友可以去看看,接下来讲解自定义view主要实现方式中的一种绘制view。
一、View绘制基本流程
1、了解绘制view的基本方法。
2、思考自己自定义View需要用到的属性
二、基本方法介绍
基本方法由三个函数完成:measure()、layout()、draw(),其内部又分别包含了onMeasure()、onLayout()、onDraw()三个子方法
1、measure()方法
在view中定义为final类型,要求子类不能修改。measure操作主要用于计算视图的大小,即视图的宽度和长度。measure()函数中又会调用onMeasure()。
onMeasure(),视图大小的将在这里最终确定,也就是说measure只是对onMeasure的一个封装,子类可以覆写onMeasure()方法实现自己的计算视图大小的方式,并通过setMeasuredDimension(width, height)保存计算结果。
2、layout()方法
在view中定义为final类型,要求子类不能修改。layout操作用于设置视图在屏幕中显示的位置。layout()函数中有两个重要方法setFrame(l,t,r,b)和onLayout()。
setFrame(l,t,r,b),l,t,r,b即子视图在父视图中的具体位置,该函数用于将这些参数保存起来
onLayout(),在View中这个函数什么都不会做,提供该函数主要是为viewGroup类型布局子视图用的;
3、draw()方法
在view中定义为final类型,要求子类不能修改,其内部定义了绘图的基本操作。draw操作利用前两部得到的参数,将视图显示在屏幕上,到这里也就完成了整个的视图绘制工作。该函数中有个重要的方法onDraw()。
注意:view中onDraw()是个空函数,具体的视图都要覆写该函数来实现自己的显示。而对于ViewGroup则不需要实现该函数,因为作为容器是“没有内容”的,其包含了多个子view,而子view已经实现了自己的绘制方法,ViewGroup只需要告诉子view绘制自己就可以了,也就是的dispatchDraw()(绘制子视图)方法;dispatchDraw()在view中这是个空函数,具体的视图不需要实现该方法,它是专门为容器类准备的,也就是容器类必须实现该方法。
三、示例
1.自定义view属性。首先在res/values/ 下建立一个attrs.xml , 在里面定义我们的属性和声明我们的整个样式。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="text" format="string" />
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
<declare-styleable name="DefineTextView">
<attr name="text" />
<attr name="textColor" />
<attr name="textSize" />
</declare-styleable>
</resources>
定义了字体,字体颜色,字体大小3个属性,format是值该属性的取值类型:string,color,demension,integer,enum,reference,float,boolean,fraction,flag;
2.在View的构造方法中,获得我们的自定义的样式
public class DefineTextView extends View {
private String mText;
private int mTextColor;
private int mTextSize;
/**
* 绘制时控制文本绘制的范围
*/
private Rect mRect;
private Paint mPaint;
public DefineTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DefineTextView(Context context) {
this(context, null);
}
public DefineTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.DefineTextView, defStyleAttr, 0);
int indexCount = typedArray.getIndexCount();
for (int i = 0; i < indexCount; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.DefineTextView_text:
mText = typedArray.getString(attr);
break;
case R.styleable.DefineTextView_textSize:
mTextSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 18, getResources().getDisplayMetrics()));
break;
case R.styleable.DefineTextView_textColor:
mTextColor = typedArray.getColor(attr, Color.BLACK);
break;
}
}
typedArray.recycle();
/**
* 获得绘制文本的宽和高
*/
mPaint = new Paint();
// mPaint.setColor(mTextColor);
mPaint.setTextSize(mTextSize);
mRect = new Rect();
mPaint.getTextBounds(mText, 0, mText.length(), mRect);
}
//重写onDraw,onMesure调用由系统提供
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(Color.GREEN);
canvas.drawRect(10, 10, getMeasuredWidth(), getMeasuredHeight(), mPaint);
mPaint.setColor(mTextColor);
canvas.drawText(mText, getWidth()/3, getHeight()/3 + mRect.height()/3, mPaint);
}
3.然后在layout布局中声明自定义View
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<demo.view.cn.viewtest.DefineTextView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="@string/hello_world"
custom:textColor="@android:color/black"
custom:text="我是小蜜蜂"
custom:textSize="10dp" />
</RelativeLayout>
注意:记得要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”。
运行效果:
如上图,我并没有对onMesure方法进行操作,系统自动实现的测量高度和宽度都是MATCH_PARNET,当我们需要设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。当设置了WRAP_CONTENT时,就需要自己进行测量,这时就需要重写onMesure方法。
代码如下:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width;
int height ;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY){
width = widthSize;
}else{
mPaint.setTextSize(mTextSize);
mPaint.getTextBounds(mText, 0, mText.length(), mRect);
float textWidth = mRect.width();
int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
width = desired;
}
if (heightMode == MeasureSpec.EXACTLY)
{
height = heightSize;
} else
{
mPaint.setTextSize(mTextSize);
mPaint.getTextBounds(mText, 0, mText.length(), mRect);
float textHeight = mRect.height();
int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
height = desired;
}
setMeasuredDimension(width, height);
}
MeasureSpec的specMode,共有三种类型:
EXACTLY:MATCH_PARENT或者是一般是设置了明确的值
AT_MOST:一般为WARP_CONTENT,表示子布局限制在一个最大值内
UNSPECIFIED:较少使用。表示子布局想要多大就多大。
xml修改如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<demo.view.cn.viewtest.DefineTextView
android:layout_width="200dp"
android:layout_height="200dp"
android:text="@string/hello_world"
custom:textColor="@android:color/black"
android:layout_centerInParent="true"
custom:text="我是小蜜蜂"
custom:textSize="10dp" />
</RelativeLayout>
运行效果:
现在我们可以对高度、宽度进行随便的设置了,符合我们的预期。
好了。整个自定义view基本完毕了,大家也可以根据自己的需求添加一些事件。
转载请附链接:
http://blog.csdn.net/haoaoo/article/details/69324829
欢迎点赞和评论。
欢迎加QQ群 378161071分享交流~~~。