android自定义View一(基础和原理)
来源:互联网 发布:云计算板块 编辑:程序博客网 时间:2024/06/07 05:58
自定义View基础和入门
http://blog.csdn.net/androidxiaogang/article/details/51849136
1、自定义View的步骤和原理
2、构造方法
自定义view的第一步是写构造方法,构造方法是用来初始化对象的,包括view也是对象。
构造方法在这里一般要写三个甚至四个,这样写的原因:我们在不同的情况下创建View的方式不同,可能需要从xml文件中填充布局,也可能不需要,或者也需要一样style之类的,因此不同情况下,使用的构造可能存在差异。因此构造方法也有这么多种类。从API上描述我们一定要有第二个构造方法。(在实际开发中也可以第一个调用第二个,第二个调用第三个构造,确保使用了每一种)
- 第一个构造:是在java创建视图的时候调用,如果从xml文件中填充,则不会调用这个构造方法;
- 第二个构造方法 :用于layout文件实例化,会把xml中的参数通过attrs带入
- 第三个构造方法:这个构造方法是在第二个基础上再传入style的
//是在java创建视图的时候调用,如果从xml文件中填充,则不会调用这个构造方法; public MyView(Context context) { super(context); Log.i(TAG,"一个参数构造"); } //用于layout文件实例化,会把xml中的参数通过attrs带入 public MyView(Context context, AttributeSet attrs) { super(context, attrs); Log.i(TAG, "二个参数构造"); } //这个构造方法是在第二个基础上再传入style的。 public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); Log.i(TAG, "三个参数构造"); }
3、 onMeasure()方法
在上图中我们指定了
setMeasuredDimension(900000000, 900000000);
但在实际onlayout()中大小为10807552
1、onMeasure计算视图大小的过程
measure是测量的意思,那么onMeasure()方法顾名思义就是用于测量视图的大小的。View系统的绘制流程会从ViewRoot的performTraversals()方法中开始,在其内部调用View的measure()方法。measure()方法接收两个参数,widthMeasureSpec和heightMeasureSpec,这两个值分别用于确定视图的宽度和高度的规格和大小。
MeasureSpec的值由specSize和specMode共同组成的,其中specSize记录的是大小,specMode记录的是规格。specMode一共有三种类型,如下所示:
1.MeasureSpec.EXACTLY
”确定是“:表示父视图希望子视图大小应该是specSize中指定的大小
2.MeasureSpec.AT_MOST
“最大是”:子视图的大小最大是specSize中指定的大小。
3.MeasureSpec.UNSPECIFIED
“没有限制”:此时View的设计者可以根据自身的特性设置视图的大小。
/** * <p> * Measure the view and its content to determine the measured width and the * measured height. This method is invoked by {@link #measure(int, int)} and * should be overridden by subclasses to provide accurate and efficient * measurement of their contents. * </p> * * <p> * <strong>CONTRACT:</strong> When overriding this method, you * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the * measured width and height of this view. Failure to do so will trigger an * <code>IllegalStateException</code>, thrown by * {@link #measure(int, int)}. Calling the superclass' * {@link #onMeasure(int, int)} is a valid use. * </p> * * <p> * The base class implementation of measure defaults to the background size, * unless a larger size is allowed by the MeasureSpec. Subclasses should * override {@link #onMeasure(int, int)} to provide better measurements of * their content. * </p> * * <p> * If this method is overridden, it is the subclass's responsibility to make * sure the measured height and width are at least the view's minimum height * and width ({@link #getSuggestedMinimumHeight()} and * {@link #getSuggestedMinimumWidth()}). * </p> * * @param widthMeasureSpec horizontal space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * @param heightMeasureSpec vertical space requirements as imposed by the parent. * The requirements are encoded with * {@link android.view.View.MeasureSpec}. * * @see #getMeasuredWidth() * @see #getMeasuredHeight() * @see #setMeasuredDimension(int, int) * @see #getSuggestedMinimumHeight() * @see #getSuggestedMinimumWidth() * @see android.view.View.MeasureSpec#getMode(int) * @see android.view.View.MeasureSpec#getSize(int) */ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
它调用了一个getDefaultSize()的方法,再来看这个方法
/** * Utility to return a default size. Uses the supplied size if the * MeasureSpec imposed no constraints. Will get larger if allowed * by the MeasureSpec. * * @param size Default size for this view * @param measureSpec Constraints imposed by the parent * @return The size this view should be. */ public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
通过onMeasure()的代码可以看出:这个方法的作用是根据父View中具体能够提供的空间大小来指定子View的视图大小,正常情况下,父View会满足子View所需要的大小,但是如果子View超过父View的最大空间,父View也只能给子View自已最大的空间。而不能无限制的满足子View。
4、onLayout()方法
onLayout()方法用于指定view在视图中的位置
/** * Called from layout when this view should * assign a size and position to each of its children. * * Derived classes with children should override * this method and call layout on each of * their children. * @param changed This is a new size or position for this view * @param left Left position, relative to parent * @param top Top position, relative to parent * @param right Right position, relative to parent * @param bottom Bottom position, relative to parent */ protected void onLayout(boolean changed, int left, int top, int right, int bottom) { }
5、为什么onMeasure(),onLayout()执行二次或者多次。
父视图可以不止一次的调用onMeasure(),onLayout()方法,如果子视图的个数为0,那么只会执行一次,如果不止一个的话,就可能执行2次或者多次。因为从xml文件或者用java代码添加子View的时候,父视图也会重新测量(给子view多大的空间)如上:第一次执行了onMeasure(),onLayout(),这时候view的宽高就发生了改变,会重新调用一次onMeasure()和onLayout()
6、onDraw()绘制内容
onDraw()把需要的内容,颜色,背景绘制到屏幕中。
demo代码
package view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.util.AttributeSet;import android.util.Log;import android.view.View;/** * Created by yu on 2016/7/7. */public class MyView extends View { public static final String TAG = "MyView"; //是在java创建视图的时候调用,如果从xml文件中填充,则不会调用这个构造方法; public MyView(Context context) { super(context); Log.i(TAG, "一个参数构造"); } //用于layout文件实例化,会把xml中的参数通过attrs带入 public MyView(Context context, AttributeSet attrs) { super(context, attrs); Log.i(TAG, "二个参数构造"); } //这个构造方法是在第二个基础上再传入style的。 public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); Log.i(TAG, "三个参数构造"); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(400, 200); Log.i(TAG, "onMeasure()"); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); Log.i(TAG, "onLayout()" + left + " : " + top + " : " + right + " : " + bottom); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.i(TAG, "onDraw()"); canvas.drawColor(Color.RED); }}
- android自定义View一(基础和原理)
- Android 自定义View(一)原理
- 自定义 View 基础和原理
- Android自定义View基础篇(一)
- Android 自定义view基础(一)
- android 自定义view 基础(一)
- Android 自定义View基础(一)
- Android 自定义View的原理与基础
- Android绘图机制(一)——自定义View的基础属性和方法
- Android绘图机制(一)——自定义View的基础属性和方法
- android 自定义View(一、基础认识)
- android自定义View基础系列一
- Android自定义View基础(一)-坐标系
- Android 自定义View(基础)
- Android 自定义View(一)
- android-自定义View(一)
- android 自定义view(一)
- Android:自定义View(一)
- JavaScript [学习笔记]
- 入职第二周的周四
- UNIX网络编程——基本UDP套接字编程
- PHP:var_dump展示不全
- 《图像识别与行为分析》产品展望
- android自定义View一(基础和原理)
- javaweb记录
- 二分法查找
- iOS 设备信息
- Java异常机制
- MapReduce 性能调优:优化洗牌(shuffle)和排序阶段
- 稀疏编码(三)
- Linux常见单词缩写
- iOS 代理委托设计模式