我知道android的view布局是树形布局的。子View需要刷新的自身界面的时候,把需求告诉父亲,则父View负责刷新、布局显示子View,从上到下。
public void invalidate() {
final ViewParent p = mParent;
final AttachInfo ai = mAttachInfo;
if (p != null && ai != null) {
final Rect r = ai.mTmpInvalRect;
// 设置刷新区域为自己的尺寸
r.set(0, 0, mRight - mLeft, mBottom - mTop);
p.invalidateChild(this, r);
}
}
从上面的代码我们可以看出:子View调用invalidate时,首先找到自己父View(View的成员变量mParent记录自己的父View),然后将AttachInfo中保存的信息告诉父View刷新自己。
View的父子关系的建立分为两种情况:
(1) View加入ViewGroup中
private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) {
...
// tell our children
if (preventRequestLayout) {
child.assignParent(this);
} else {
child.mParent = this;
}
...
}
2)DecorView注册给WindowManagerImpl时,产生一个ViewRoot作为其父View。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView){
.....
view.assignParent(this);
....
}
AttachInfo是在View第一次attach到Window时,ViewRoot传给自己的子View的。这个AttachInfo之后,会顺着布局体系一直传递到最底层的View。
View.java
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
.....
}
ViewGroup.java
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
super.dispatchAttachedToWindow(info, visibility);
for (int i = 0; i < count; i++) {
children[i].dispatchAttachedToWindow(info, visibility);
}
}
并且在新的View被加入ViewGroup时,也会将该AttachInfo传给加入的View
ViewGroup.java
private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) {
child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
}
到这里明白了mParent与AttachInfo代表的意义,可以继续刷新过程的分析。
在invalidate中,调用父View的invalidateChild,这是一个从第向上回溯的过程,每一层的父View都将自己的显示区域与传入的刷新Rect做交集。
public final void invalidateChild(View child, final Rect dirty) {
ViewParent parent = this;
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
final int[] location = attachInfo.mInvalidateChildLocation;
// 需要刷新的子View的位置
location[CHILD_LEFT_INDEX] = child.mLeft;
location[CHILD_TOP_INDEX] = child.mTop;
// If the child is drawing an animation, we want to copy this flag onto
// ourselves and the parent to make sure the invalidate request goes through
final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
// Check whether the child that requests the invalidate is fully opaque
final boolean isOpaque = child.isOpaque() && !drawAnimation && child.getAnimation() != null;
// Mark the child as dirty, using the appropriate flag
// Make sure we do not set both flags at the same time
final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
do {
View view = null;
if (parent instanceof View) {
view = (View) parent;
}
if (drawAnimation) {
if (view != null) {
view.mPrivateFlags |= DRAW_ANIMATION;
} else if (parent instanceof ViewRoot) {
((ViewRoot) parent).mIsAnimating = true;
}
}
// If the parent is dirty opaque or not dirty, mark it dirty with the opaque
// flag coming from the child that initiated the invalidate
if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
}
parent = parent.invalidateChildInParent(location, dirty);
} while (parent != null);
}
}
public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
if ((mPrivateFlags & DRAWN) == DRAWN) {
if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
FLAG_OPTIMIZE_INVALIDATE) {
// 根据父View的位置,偏移刷新区域
dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX, location[CHILD_TOP_INDEX] - mScrollY);
final int left = mLeft;
final int top = mTop;
//计算实际可刷新区域
if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
(mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
mPrivateFlags &= ~DRAWING_CACHE_VALID;
location[CHILD_LEFT_INDEX] = left;
location[CHILD_TOP_INDEX] = top;
return mParent;
}
} else {
mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
location[CHILD_LEFT_INDEX] = mLeft;
location[CHILD_TOP_INDEX] = mTop;
dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
mBottom - location[CHILD_TOP_INDEX]);
return mParent;
}
}
return null;
}
这个向上回溯的过程直到ViewRoot那里结束,由ViewRoot对这个最终的刷新区域做刷新。
ViewRoot.java
public void invalidateChild(View child, Rect dirty) {
scheduleTraversals();
}
分享到:
相关推荐
基于SYSTEMVIEW通信原理实验报告北邮通信原理实验
用MATLAB 通信系统仿真,包括模拟调幅,调频,调相,数字编码,数字调制技术等等。内含源码及注释。
通原实验仿真,共十个,全部可用,基本的模拟和数字调制方法都有,希望对大家有所帮助。
ListView布局之View复用原理举例
事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务原理MVCC、Readview和行锁原理分析直播中(1).zip事务...
通信原理 2PSK 仿真 SystemView 通信原理 2PSK 仿真 SystemView 通信原理 2PSK 仿真 SystemView
BB VIEW 原理图
通信原理System view 仿真实例,用System view软件将通信原理教程的各个章节进行了仿真,可以复制通信技术学习
Vue router-view和router-link的实现原理 使用 <div id="app"> 首页</router-link> 关于</router-link> <router-view a=1><router-view/> </div> router-view组件 export default { //函数式组件没有...
北邮通信原理实验基于SYSTEMVIEW通信原理实验报告
学习Systemview仿真软件,培养学生基本掌握电路设计的基本思路和方法,对需要仿真的通信系统各功能模块的工作原理进行分析。 a.二进制振幅键控(2ASK)系统的设计 b.二进制移频键控(2FSK)系统的设计 c.二进制移...
通信原理实验五--二进制差分相移键控 DPSK--Systemview仿真.rar 资源包括:DPSK的调制、解调和相比较法解调DPSK 实验目的 1、掌握 DPSK 调制和解调的基本原理; 2、掌握 DPSK 数据传输过程,熟悉典型电路; 3、...
http://blog.csdn.net/qq_26787115/article/details/53428258
Systemview是美国ELANIX公司于1995年开始推出的软件工具,它为用户提供了一个完整的动态系统设计、仿真与分析的可视化软件环境,能进行模拟、数字、数模混合系统、线性和非线性系统的分析设计,可对线性系统进行拉氏...
它是以systemview为软件平台,来实现通信原理中的信号的编码解码、调制、传输等相关的特性。
绪论 2 SystemView及其操作简介 3 ...3.1 16QAM系统基本原理 27 3.2 16QAM产生的方法 27 3.3 16QAM信号的解调方法 28 3.4 16QAM的信号空间 29 3.5 16QAM调制系统仿真设计 30 小结 33 附录 34 谢辞 34 参考文献 34
什么是自定义View 为什么使用自定义View 如何自定义控件