View总结(1)---onMeasure(),onLayout(),onDraw()方法
来源:互联网 发布:淘宝个人店铺 注册商标 编辑:程序博客网 时间:2024/05/17 07:21
View总结
本文是在阅读http://blog.csdn.net/qinjuning 和
http://www.idtkm.com/2016/08/10/10%E3%80%81RequestLayout/的一些总结思考
View绘制过程
附上一张流程图(图片来源https://plus.google.com/photos/photo/115089607132986274709/5801812726909061186)
onMeasure()方法
作用:测量View与ChildView的大小
onMeasure()的函数模型
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
widthMeasureSpec和heightMeasureSpec共32bit,前2bit记录了测量模式,后30bit记录了View尺寸信息,可以通过下面方法获得相应的值。测量模式有三种:UNSPECIFIED,EXACTLY,AL_MOST。
int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);
onMeasure()源码
//回调View视图里的onMeasure过程 private void onMeasure(int height , int width){ //设置该view的实际宽(mMeasuredWidth)高(mMeasuredHeight) //1、该方法必须在onMeasure调用,否者报异常。 setMeasuredDimension(h , l) ; //2、如果该View是ViewGroup类型,则对它的每个子View进行measure()过程 int childCount = getChildCount() ; for(int i=0 ;i<childCount ;i++){ //2.1、获得每个子View对象引用 View child = getChildAt(i) ; //整个measure()过程就是个递归过程 //该方法只是一个过滤器,最后会调用measure()过程 ;或者 measureChild(child , h, i)方法都 measureChildWithMargins(child , h, i) ; //其实,对于我们自己写的应用来说,最好的办法是去掉框架里的该方法,直接调用view.measure(),如下: //child.measure(h, l) } } //该方法具体实现在ViewGroup.java里 。 protected void measureChildWithMargins(View v, int height , int width){ v.measure(h,l) }
重写onMeasure()方法—实现效果:View的宽高相等,默认为100像素。
private int getSize(int defaultSize, int measureSpec){ int mySize = defaultSize; int mode = MeasureSpec.getMode(measureSpec); int size = MeasureSpec.getSize(measureSpec); switch (mode){ case MeasureSpec.UNSPECIFIED:{ //如果没有指定大小,就设置为默认大小 mySize = defaultSize; break; } case MeasureSpec.EXACTLY:{ mySize = size; break; } case MeasureSpec.AT_MOST:{ mySize = size; break; } } return mySize; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); width = getSize(100, widthMeasureSpec); height = getSize(100, heightMeasureSpec); if(width > height){ width = height; }else{ height = width; } //传入的是View最终的视图大小 setMeasuredDimension(width, height); Log.d("onMeasure", "width = "+width+"; height = "+height); }
onLayout()方法
作用:确定View的位置,设置View试图位于父视图的坐标轴,即mLeft, mRight, mTop, mBottom(调用setFrame()方法实现)。
// layout()过程 ViewRoot.java // 发起layout()的"发号者"在ViewRoot.java里的performTraversals()方法, mView.layout() private void performTraversals(){ //... View mView ; mView.layout(left,top,right,bottom) ; //.... } //回调View视图里的onLayout过程 ,该方法只由ViewGroup类型实现 private void onLayout(int left , int top , right , bottom){ //如果该View不是ViewGroup类型 //调用setFrame()方法设置该控件的在父视图上的坐标轴 setFrame(l ,t , r ,b) ; //-------------------------- //如果该View是ViewGroup类型,则对它的每个子View进行layout()过程 int childCount = getChildCount() ; for(int i=0 ;i<childCount ;i++){ //2.1、获得每个子View对象引用 View child = getChildAt(i) ; //整个layout()过程就是个递归过程 child.layout(l, t, r, b) ; } }
onDraw()方法
作用:由ViewRoot对象的performTraversals()方法调用draw()方法绘制View树,但只会绘制View内部包含标志位DRAWN的树,即”需要重绘”的树。
onDraw()源码
// draw()过程 ViewRoot.java // 发起draw()的"发号者"在ViewRoot.java里的performTraversals()方法, 该方法会继续调用draw()方法开始绘图 private void draw(){ //... View mView ; mView.draw(canvas) ; //.... } //回调View视图里的onLayout过程 ,该方法只由ViewGroup类型实现 private void draw(Canvas canvas){ //该方法会做如下事情 //1 、绘制该View的背景 //2、为绘制渐变框做一些准备操作 //3、调用onDraw()方法绘制视图本身 //4、调用dispatchDraw()方法绘制每个子视图,dispatchDraw()已经在Android框架中实现了,在ViewGroup方法中。 // 应用程序程序一般不需要重写该方法,但可以捕获该方法的发生,做一些特别的事情。 //5、绘制渐变框 } //ViewGroup.java中的dispatchDraw()方法,应用程序一般不需要重写该方法 @Override protected void dispatchDraw(Canvas canvas) { // //其实现方法类似如下: int childCount = getChildCount() ; for(int i=0 ;i<childCount ;i++){ View child = getChildAt(i) ; //调用drawChild完成 drawChild(child,canvas) ; } } //ViewGroup.java中的dispatchDraw()方法,应用程序一般不需要重写该方法 protected void drawChild(View child,Canvas canvas) { // .... //简单的回调View对象的draw()方法,递归就这么产生了。 child.draw(canvas) ; //......... }
重写onDraw的几点说明:
1. 自定义布局属性
在res/values/styles.xml中创建自己的自定义属性:
<declare-styleable name="DoubanLoadingView"> <attr name="my_size" format="dimension" /></declare-styleable>
接着即可在布局文件中声明自定义属性:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.hc.douban.DoubanLoadingView android:layout_width="match_parent" android:layout_height="100dp" app:my_size="100dp" /></LinearLayout>
PS: 注意添加”http://schemas.android.com/apk/res-auto”
最后可以在自定义的View中将自定义的属性取出来:
private int defalutSize; public MyView(Context context, AttributeSet attrs) { super(context, attrs); //第二个参数就是我们在styles.xml文件中的<declare-styleable>标签 //即属性集合的标签,在R文件中名称为R.styleable+name TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DoubanLoadingView); //第一个参数为属性集合里面的属性,R文件名称:R.styleable+属性集合名称+下划线+属性名称 //第二个参数为,如果没有设置这个属性,则设置的默认的值 defalutSize = a.getDimensionPixelSize(R.styleable.DoubanLoadingView_my_size, 100); //最后记得将TypedArray对象回收 a.recycle(); }
- View总结(1)---onMeasure(),onLayout(),onDraw()方法
- view的onlayout,onmeasure,ondraw
- 自定义View中的方法onMeasure,onLayout,onDraw作用
- 自定义View(三) 之 onMeasure() onLayout() onDraw()
- 自定义View之onMeasure(),onLayout(),onDraw()
- 自定义View中的onMeasure,onLayout,onDraw
- 自定义View中的onMeasure,onLayout,onDraw
- view的onMeasure,onLayout,onDraw源码分析
- 自定义view之onMeasure,onLayout,onDraw
- onMeasure(),onLayout(),onDraw(),invalidate()方法详解
- onMeasure(),onLayout(),onDraw
- onMeasure,onLayout,onDraw
- onMeasure onLayout onDraw
- 自定义view中onMeasure、onLayout、onDraw、onFinishInflate、onSizeChanged方法调用时机
- 安卓开发中自定义View之onMeasure(),onLayout(),onDraw()讲解(一)
- 安卓开发中自定义View之onMeasure(),onLayout(),onDraw()讲解(二)
- 安卓开发中自定义View之onMeasure(),onLayout(),onDraw()讲解(三)
- 关于View的onMeasure()、onSizeChanged()、onLayout()、onDraw()调用顺序
- python学习—Day44—多线程共享变量与线程池
- Java设计模式之命令模式
- 数据结构年终总结
- ionic 侧拉框
- 十分钟学会写Shell脚本
- View总结(1)---onMeasure(),onLayout(),onDraw()方法
- 会议记录管理系统(2)
- Mycat心跳机制梳理
- 加密货币总市值突破5000亿美元,超越股神公司市值
- Tensorflow中的优化器子类
- linux下qt虚拟键盘
- 2007年总结与2008年规划
- 12月14日学习笔记-几个练习题
- 学生成绩管理系统