View绘制3-onLayout
来源:互联网 发布:ae软件中文版免费版 编辑:程序博客网 时间:2024/04/29 14:08
作用
在执行完成onMeasure()
确定了View的大小后,需要执行onLayout()
来确定View的位置
实现
先看View的layout()
方法
public void layout(int l, int t, int r, int b) { if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; } int oldL = mLeft; int oldT = mTop; int oldB = mBottom; int oldR = mRight; boolean changed = isLayoutModeOptical(mParent) ? setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { onLayout(changed, l, t, r, b); mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; ListenerInfo li = mListenerInfo; if (li != null && li.mOnLayoutChangeListeners != null) { ArrayList<OnLayoutChangeListener> listenersCopy = (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); int numListeners = listenersCopy.size(); for (int i = 0; i < numListeners; ++i) { listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); } } }
setFrame方法会先把l,t,r,b设置给mLeft,mTop,mRight,mBottom,一个View他的4个第多年确认了,那么View本身位置也就确认了。
然后比较位置是否和之前的位置发生改变,如果发生改变就调用onLayout()
方法
onLayout()方法
查看View的onLayout()方法
/** * Called from layout when this view should * assign a size and position to each of its children. */ protected void onLayout(boolean changed, int left, int top, int right, int bottom) { }
发现这个方法是个空实现,但是注释说,onLayout()方法被用于指定子View,View的父ViewGroup实现
@Override protected abstract void onLayout(boolean changed, int l, int t, int r, int b);
发现ViewGroup中是一个抽象方法
其实很好理解,如果一个在父容器中确定子View的位置必然是一种具体情况,需要具体的布局去实现,
以LinearLayout为例
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); } else { layoutHorizontal(l, t, r, b); } }
通过布局方向的不同分为layoutVertical(l, t, r, b)
和layoutHorizontal(l, t, r, b)
void layoutVertical(int left, int top, int right, int bottom) { final int paddingLeft = mPaddingLeft; int childTop; int childLeft; // Where right end of child should go final int width = right - left; int childRight = width - mPaddingRight; int childSpace = width - paddingLeft - mPaddingRight; final int count = getVirtualChildCount(); // 省略 ... for (int i = 0; i < count; i++) { final View child = getVirtualChildAt(i); if (child == null) { childTop += measureNullChild(i); } else if (child.getVisibility() != GONE) { final int childWidth = child.getMeasuredWidth(); final int childHeight = child.getMeasuredHeight(); final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child .getLayoutParams(); final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); // 省略 ... if (hasDividerBeforeChildAt(i)) { childTop += mDividerHeight; } childTop += lp.topMargin; setChildFrame(child, childLeft, childTop + getLocationOffset(child), childWidth, childHeight); childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child); i += getChildrenSkipCount(child, i); } } }
a. 获取child可用的空间,child的个数,由上自下逐个遍历
b. 获得左上角顶点后,根据onMeasure中获得的宽高,就可以计算出其他3个点的位置,然后通过setChildFrame()
方法执行确定子控件的位
c. 同时继续遍历直到结束
d. setChildFrame方法体
private void setChildFrame(View child, int left, int top, int width, int height) { child.layout(left, top, left + width, top + height); }
其实就是调用的child的layout方法,如果child也是一个容器那么子元素有可以通过子元素的onLayout方法去确定他的孙元素,从而整个执行过程就完成了
注意事项
1.一般情况下getWidth()和 getMeasureWidth( )返回的值是一样的,不过存在特殊情况,复杂布局,例如改写layout方法
public void layout(int l, int t, int r, int b) { super.layout(l, t + 100, b, r + 100); }
这样View的实际getTop和getBottom就比Measure多100.
2.继承ViewGroup来实现onLayout()往往特别复杂,本着不重复发明轮子的原则,使用已有的来实现如LinearLayout RelativeLayout
参考:《Android开发艺术探讨》任玉刚
- View绘制3-onLayout
- 自定义View-3-重写onLayout
- Android中View的绘制过程 onMeasure和onLayout()方法
- 自定义view中的onLayout
- 自定义view onLayout
- 自定义View的onMeasure、onLayout
- view的onlayout,onmeasure,ondraw
- 自定义View初探-onLayout详解
- Android7.0 自定义控件addView(...)无效,View的绘制流程(onMeasure、onLayout等)完全没执行的解决办法。
- (总结篇)Android 牛不牛?决定于自定义View控件(一)——view绘制流程(onMeasure,onLayout,onDraw)
- 视图的绘制过程 onMeasure()、onLayout()、dispatchDraw()
- 自定义View(3)——onLayout()、onDraw()方法的简单使用
- 自定义View(三) 之 onMeasure() onLayout() onDraw()
- 自定义View之onMeasure(),onLayout(),onDraw()
- 自定义View中的onMeasure,onLayout,onDraw
- 自定义View中的onMeasure,onLayout,onDraw
- 【自定义View系列】03--onLayout源码分析
- View,ViewGroup的onMeasure与onLayout
- Node入门
- 全景视频拼接关键技术
- socket编程:多路复用之select
- [POJ 1862] Stripies (贪心)
- emWin皮肤设置颜色
- View绘制3-onLayout
- 【bzoj3506】【CQOI2014】排序机械臂
- 【HDU5482】Numquam vincar,暴力(da biao)预处理+组合数
- Objective-C ---NSFileManager NSFileHandle (梳理整理)
- python中的目录递归的创建和目录及其下的文件递归的删除
- 设计模式之原型模式(C++实现)
- 李开复教你如何发现自己的兴趣爱好
- Tomcat 6.0 配置oracle数据库连接池
- Octave 线性代数 矩阵的秩与线性方程组 1