您的位置:首页 > 其它

自定义View(View的绘制与测量)

2016-04-11 23:03 169 查看
该博文由笔者学习徐宜生的《Android群英会》总结而成的。

View的测量

在绘制View之前,我们需要思考一下,系统是如何绘制这些View的,就好比在现实生活中,我们要去画一个图形,就必须知道我们要画的位置和大小。同样Android在绘制View前,也必须对View进行测量,这些都是在自定义View时重写onMeasure()方法,在其中完成。

测量模式有三种:

- EXACTLY

精确模式,当控件的layout_width和layout_height属性指定为具体值时,例如:layout_width:”100dp”,或者指定为match_parent时,系统使用的是EXACTLY模式

- AT_MOST

最大值模式,当控件的layout_width和layout_height属性指定为wrap_content时,控件的大小一般随着子控件的大小变化而变化,此时控件的尺寸只要不超过父类即可。

- UNSPECIFIED

它不指定其大小的测量模式,View想多大就多大,通常情况下在自定义View时使用。

注意:View类默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法,就只能使用EXACTLY模式(即必须确定layout_width和layout_height属性的值,layout_width:”100dp”或layout_width:”match_parent”)。而如果在自定义View时layout_width和layout_height属性的值为wrap_content,就必须重写onMeasure()方法指定wrap_content的大小。

下面通过代码来进行讲解

重写onMeasure()方法:

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}


通过setMeasuredDimention(int measuredWidth,measuredHeight)方法将测量后的宽高值设置进去

protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){
setMeasuredDimention(measureWidth(widthMeasureSpec),measuredHeight(heightMeasureSpec));
}


我们自己定义了两个方法measureWidth(widthMeasureSpec)和measuredHeight(heightMeasureSpec)对宽高重新定义,参数则是宽和高的MeasureSpec对象,MeasureSpec包含了测量的模式(mode)和测量的大小(size)

public int measureWidth(int widthMeasureSpec){
int mode=MeasureSpec.getMode(widthMeasureSpec);
int size=MeasureSpec.getSize(widthMeasureSpec);
int result=0;
if(mode==MeasureSpec.EXACTLY){
result=size;
if(mode==MeasureSpec.AT_MOST){
result=Max.min(200,size);//200是根据自己需求自定义的
}
}
return result;
}


measuredHeight(heightMeasureSpec)实现原理同measureWidth(widthMeasureSpec)相同,在这里不再啰嗦啦。

此时,我们就完成了对宽高的测量,以上代码可以作为一个模板代码复制到自己的项目中使用。

View的绘制

绘制需要重写onDraw()方法

这里需要用到Android两个对象Canvas和Paint,Canvas相当于画家使用的画板,而Paint相当于画家手中的画笔

在onDraw()方法中使用Canvas对象进行绘图

canvas.drawXXXX;

这里可以绘制多种图形,圆,线,矩形,Bitmap等。

自定义View

通常在自定义View中有一些重要的回调方法:

onFinishInflate():在布局文件加载该自定义View后回调

onSizeChanged(int w, int h, int oldw, int oldh):组件大小改变时回调该方法

onMeasure(int widthMeasureSpec, int heightMeasureSpec):对自定义View进行测量

onLayout(boolean changed, int left, int top, int right, int bottom):确定显示的位置

onTouchEvent(MotionEvent event):监听触摸事件的发生

最重要就是onDraw(Canvas canvas):对自定义View进行绘制

java代码:

package com.example.dong.studydemo;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;

/**
* Created by Administrator on 2016/4/12.
*/
public class CustomTextView extends TextView {

private Paint paint1, paint2;

public CustomTextView(Context context) {
super(context);
}

public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}

public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
}

private int measureWidth(int widthMeasureSpec) {
int result = 0;
int mode = MeasureSpec.getMode(widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);

if (mode == MeasureSpec.EXACTLY) {
result = size;
} else if (mode == MeasureSpec.AT_MOST) {
result = Math.min(150, size);
}

return result;
}

private int measureHeight(int heightMeasureSpec) {
int result = 0;
int mode = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);

if (mode == MeasureSpec.EXACTLY) {
result = size;
} else if (mode == MeasureSpec.AT_MOST) {
result = Math.min(100, size);
}

return result;
}

@Override
protected void onDraw(Canvas canvas) {
paint1 = new Paint();
paint1.setColor(Color.RED);
paint1.setStyle(Paint.Style.FILL);

paint2 = new Paint();
paint2.setColor(Color.BLACK);
paint2.setStyle(Paint.Style.FILL);

canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint1);
canvas.drawRect(60, 60, getMeasuredWidth() - 60, getMeasuredHeight() - 60, paint2);

canvas.save();
super.onDraw(canvas);
canvas.restore();

}

}


注意:这里绘制了两个不同颜色、不同大小的矩形,是在调用super.onDraw(canvas)方法前绘制,使得两个矩形位于文字的下方,然后系统再调用super.onDraw(canvas)方法绘制文字,文字此时处于最上方。

布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<com.example.dong.studydemo.CustomTextView
android:id="@+id/tv"
android:layout_width="150dp"
android:layout_height="100dp"
android:gravity="center"
android:text="哈哈哈"
android:textColor="#fff" />
</LinearLayout>


最终呈现效果



本人很少写博文,技术谈不上大神水平,不足之处,还望多多包涵!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: