Android View和动画--笔记

来源:互联网 发布:vb中array是什么意思 编辑:程序博客网 时间:2024/06/06 10:06

ListView:

ListView并不会为每个item都建新的view实例,而是采用复用的方式。将屏幕上看不见的view复用。

实现模式: adpter模式,观察者模式,view的复用机制。

GridView的原理同ListView一样,而且adpter可以互用。

RecyclerView:
比listview和gridview更加灵活。

自定义View

自定义view中比较重要的是measure layout draw过程,以及处理事件,动画等。

实现自定义View的步骤:
1.继承View
2.如果需要自定义View属性,在values中定义属性集
3.在代码中读取属性,初始化视图
4.测量onMesure,由于View是叶子结点,所以不用布局子视图
5.绘制 onDraw

在视图树的绘制过程中,开始于ViewRoot的performTraversals方法,此方法里面会调用measure方法,进行测量,测量结束后是布局和绘制。measure方法会接受两个参数,widthMeasureSpec和heightMeasureSpec,是MeasureSpec类型,MeasureSpec游两部分组成,specSize和specMode,specSize是大小,specMode是模式。
specMode主要有三种:

EXACTLY:
具体的值,表示父视图希望子视图的大小由specSize决定。match_parent和具体的数值对应的都是EXACTLY

AT_MOST
表示子视图最多是specSize大小。wrap_content对应这种模式

UNSPECIFIED
表示可以设置成任意的大小,不常用。

onMeasure
在onMeasure函数中,根据传入进来的MeasureSpec类型的值,算好视图的大小后,需要通过setMeasuredDimension函数设置。

View的绘制
view的绘制是在Canvas上绘制的,而绘制Canvas是需要画笔Paint的。可以在Canvas上绘制矩形、文本、线、路径、椭圆、图片、裁剪矩形(后续操作只在矩形内有效)等。

可以通过查一下Canvas的api看下相关的api。平移,裁剪,旋转,倾斜skew,放缩,保存,恢复等。

整个View树的绘图流程是在ViewRootImpl类的performTraversals()方法(这个方法巨长)开始的,该函数做的执行过 程主要是根据之前设置的状态,判断是否重新计算视图大小(measure)、是否重新放置视图的位置(layout)、以及是否重绘 (draw),其核心也就是通过判断来选择顺序执行这三个方法中的哪个

private void performTraversals() {        ......        //最外层的根视图的widthMeasureSpec和heightMeasureSpec由来        //lp.width和lp.height在创建ViewGroup实例时等于MATCH_PARENT        int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);        int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);        ......        mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);        ......        mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());        ......        mView.draw(canvas);        ......    }

view的绘制流程(转)

测量Measure过程(转)

MeasureSpec由两部分组成,高16位表示MODE,定义在 MeasureSpec类(View的内部类)中,有三种类型,MeasureSpec.EXACTLY表示确定大小, MeasureSpec.AT_MOST表示最大大小, MeasureSpec.UNSPECIFIED不确定。低16位表示size,也就是父View的大小。

这是一种设计模式,在平时设计中可以采纳,通过位运算就可以取出MODE和SIZE,比较简洁。

layout过程

layout的实质是调用setFrame方法把参数分别赋值给mLeft、mTop、mRight和mBottom这几个变量

View的layout方法是可以在子类重写的,而 ViewGroup的layout是不能在子类重写的,言外之意就是说ViewGroup中只能通过重写onLayout方法。

到这里就不得不提getWidth()、getHeight()和getMeasuredWidth()、getMeasuredHeight() 这两对方法之间的区别(上面分析measure过程已经说过getMeasuredWidth()、getMeasuredHeight()必须在 onMeasure之后使用才有效)。可以看出来getWidth()与getHeight()方法必须在layout(int l, int t, int r, int b)执行之后才有效

绘制draw过程

绘制过程

/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas’ layers to prepare for fading
* 3. Draw view’s content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/

// skip step 2 & 5 if possible (common case)

draw原理总结

可以看见,绘制过程就是把View对象绘制到屏幕上,整个draw过程需要注意如下细节:

如果该View是一个ViewGroup,则需要递归绘制其所包含的所有子View。
View默认不会绘制任何内容,真正的绘制都需要自己在子类中实现。
View的绘制是借助onDraw方法传入的Canvas类来进行的。
区分View动画和ViewGroup布局动画,前者指的是View自身的动画,可以通过setAnimation添加,后者是专门针对 ViewGroup显示内部子视图时设置的动画,可以在xml布局文件中对ViewGroup设置layoutAnimation属性(譬如对 LinearLayout设置子View在显示时出现逐行、随机、下等显示等不同动画效果)。
在获取画布剪切区(每个View的draw中传入的Canvas)时会自动处理掉padding,子View获取Canvas不用关注这些逻辑,只用关心如何绘制即可。
默认情况下子View的ViewGroup.drawChild绘制顺序和子View被添加的顺序一致,但是你也可以重载ViewGroup.getChildDrawingOrder()方法提供不同顺序

invalidate与postInvalidate方法

这里写图片描述

这里写图片描述
invalidate系列方法请求重绘View树(也就是draw方法),如果View大小没有发生变化就不会调用layout过程,并且只绘制那 些“需要重绘的”View,也就是哪个View(View只绘制该View,ViewGroup绘制整个ViewGroup)请求invalidate系 列方法,就绘制该View。

当我们触发View的requestLayout时其实质就是层层向上传递,直到ViewRootImpl为止,然后触发ViewRootImpl的requestLayout方法,如下就是ViewRootImpl的requestLayout方法:

通过置了一个标记,mLayoutRequested = true;requestLayout()方法会调用measure过程和layout过程,不会调用draw过程,也不会重新绘制任何View包括该调用者本身。

练习:RecyclerView的使用,包括LayoutManager,ItemDecotation为item view添加装饰,比如添加动画。

参考:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0603/2983.html

0 0
原创粉丝点击