说明:本博客为原创,转载请注明出处 CSDN-ANDROID笔记栈
由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正
索引
onLayout
自定义View继承ViewGroup必须要实现这个方法,该方法实现了所有子View的具体位置
protected void onLayout(boolean changed, int left, int top, int right, int bottom){
// changed,如果View大小改变 或者位置改变为true
// left,top,right,bottom 是左上右下值,这个值是相对于它的ParentView而言的。
//View的大小是基于一个矩形来确定的,四个点可以确定一个矩形的位置及大小。
// 10,10,30,40的意思是当前View距离ParentView的左边距为10,上边距为10,当前View的宽度为20,高度为30
}
//真正的layout入口是layout方法
public void layout(int l, int t, int r, int b){
...
onLayout();
...
}
Demo
GitHub地址: GitHub
环境: Windows7+JAVA8
IDE: AndroidStdio2.2.2
compileSdkVersion:24
测试设备:Nexus5(6.0.1)
运行结果截图
自定义ViewGroup实现了如图所示的布局
//xml源码
...
//DLCustomViewGroup 宽高都是match_parent的,但是在onMeasure方法中改变了这个值
<com.neulion.android.dl.customviewdemo.widget.DLCustomViewGroup
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffeb3b">
<com.neulion.android.dl.customviewdemo.widget.DLCustomView
android:layout_width="48dp"
android:layout_height="48dp"
android:background="#ff0000" />
<com.neulion.android.dl.customviewdemo.widget.DLCustomView
android:layout_width="48dp"
android:layout_height="48dp"
android:background="#00ff00" />
<com.neulion.android.dl.customviewdemo.widget.DLCustomView
android:layout_width="48dp"
android:layout_height="48dp"
android:background="#0000ff" />
<com.neulion.android.dl.customviewdemo.widget.DLCustomView
android:layout_width="48dp"
android:layout_height="48dp"
android:background="#000000" />
</com.neulion.android.dl.customviewdemo.widget.DLCustomViewGroup>
...
// DLCustomViewGroup部分源码
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
//ViewGroup自己测量所有子View的大小,该方法是ViewGroup自带的
measureChildren(widthMeasureSpec, heightMeasureSpec);
//计算所有子View的高度(类似于LinearLayout垂直布局)
int childrenHeight = 0;
//遍历所有子View
for (int i = 0; i < getChildCount(); i++){
childrenHeight += getChildAt(i).getMeasuredHeight();
}
//height并没有解析xml属性,这里只是做个测试
//在这里应该基于XML布局的属性,子View的大小,ViewGroup实现的布局等来确定最后的大小!
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), childrenHeight);
}
最后看下onLayout方法源码
void layoutChildren(int left, int top, int right, int bottom)
{
final int count = getChildCount();
//child 初始left,top值
int childLeft = left + getPaddingLeft();
int childTop = top + getPaddingTop();
//遍历所有子View
for (int i = 0; i < count; i++)
{
final View child = getChildAt(i);
//这里所有的子View应该是已经被测量好了的!
int childRight = childLeft + child.getMeasuredWidth();
int childBottom = childTop + child.getMeasuredHeight();
//摆放View的具体位置
child.layout(childLeft, childTop, childRight, childBottom);
//下一个View的Left就是当前View的Right
childLeft = childRight;
childTop = childBottom;
}
}