自定义View(View的绘制与测量)
2016-04-11 23:03
169 查看
该博文由笔者学习徐宜生的《Android群英会》总结而成的。
测量模式有三种:
- 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()方法:
通过setMeasuredDimention(int measuredWidth,measuredHeight)方法将测量后的宽高值设置进去
我们自己定义了两个方法measureWidth(widthMeasureSpec)和measuredHeight(heightMeasureSpec)对宽高重新定义,参数则是宽和高的MeasureSpec对象,MeasureSpec包含了测量的模式(mode)和测量的大小(size)
measuredHeight(heightMeasureSpec)实现原理同measureWidth(widthMeasureSpec)相同,在这里不再啰嗦啦。
此时,我们就完成了对宽高的测量,以上代码可以作为一个模板代码复制到自己的项目中使用。
这里需要用到Android两个对象Canvas和Paint,Canvas相当于画家使用的画板,而Paint相当于画家手中的画笔
在onDraw()方法中使用Canvas对象进行绘图
canvas.drawXXXX;
这里可以绘制多种图形,圆,线,矩形,Bitmap等。
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代码:
注意:这里绘制了两个不同颜色、不同大小的矩形,是在调用super.onDraw(canvas)方法前绘制,使得两个矩形位于文字的下方,然后系统再调用super.onDraw(canvas)方法绘制文字,文字此时处于最上方。
布局文件
最终呈现效果
![](http://img.blog.csdn.net/20160412212118172)
本人很少写博文,技术谈不上大神水平,不足之处,还望多多包涵!
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>
最终呈现效果
本人很少写博文,技术谈不上大神水平,不足之处,还望多多包涵!
相关文章推荐
- 整数数组中子数组的最大值2
- linux文件系统---10
- ZZuoj1865(贪心)
- Javascript中的装饰者模式以及AOP简介
- Qt学习之2D绘图(画刷和画笔)
- Java web 中文件下载遇到的缓冲大小问题
- jQuery对AJAX的封装——$.ajax
- FastJSON 简介及其Map/JSON/String 互转
- java ssm框架入门(一)面向接口编程
- 网络并发服务器设计---9
- lena,知识从未如此性感
- Java入门 第一季第五章 编程练习解析
- IPV4和IPV6的区别
- Android Studio在线更新
- 第三次上机作业
- 多列居中等高布局
- linux脚本编程技术---8
- MySQL导入.sql文件时出现" failed to open file"错误
- 队
- css3百叶窗轮播图效果