说明:本博客为原创,转载请注明出处 -ANDROID笔记栈 由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正
索引
onLayoutDemo自定义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(); ... }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; } }