首页 > 代码库 > HackThree
HackThree
创建自定义ViewGroup
?一,概要:
使用自定义View 和ViewGroup组织应用程序布局是一个好方法,定制组件的同时允许开发者提供自定义行为和功能,以后,开发者
在需要创建复杂布局的视乎,首先应该考虑使用自定义ViewGroup是不是更适合,虽然在开始时,这样做会增加一定的工作量,但是,这是值得的
?二,基本知识点:
要想绘制自定义ViewGroup要涉及到两个方法:
measure(int , int):该方法从上到下遍历视图树。在递归遍历过程中,每个视图都会从下层传递尺寸和规格。当measure方法遍历结束,每个视图都保存了各自的尺寸信息。
layout(int, int, int, int):该方法也是从上而下遍历视图树,在遍历过程中,每个父视图通过测量过程的结果定位所有子视图的位置信息。
思路整理:
- 要设置每个子View的横向偏移和竖向偏移普通的android属性中没有,所以需要自定义属性来获取值后来进行设置
- 通过复写ViewGroup中的onMeasure(int,int)方法测量Viewgroup和子View的大小,从而利用onLayout(int,int,int,int)来放置到具体区域
三.效果图:
四.代码:
1)自定义属性,在res/values中没有attr.xml文件就新建一个
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <declare-styleable name="myrectangle"> 5 <attr name="horizontal_distance" format="dimension" /> 6 <attr name="verticle_distance" format="dimension" /> 7 </declare-styleable> 8 <declare-styleable name="MyLayoutParams"> 9 <attr name="layout_verticle_distance" format="dimension" />10 </declare-styleable>11 12 </resources>
2)设置这些属性未指定时的默认值大小,在dimens.xml中添加:
1 <dimen name="myRectangle_horizontal_distance">10dp</dimen>2 <dimen name="myRectangle_verticle_distance">10dp</dimen>
3)自定义ViewGroup
1 public class MyViewGoup extends ViewGroup { 2 3 private int mHorzntialDistance; 4 5 private int mVerticalDIstance; 6 7 public MyViewGoup(Context context) { 8 super(context); 9 } 10 11 public MyViewGoup(Context context, AttributeSet attrs) { 12 super(context, attrs); 13 /** 14 * 获取自定义属性值 15 */ 16 TypedArray a = context.obtainStyledAttributes(attrs, 17 R.styleable.myrectangle); 18 try { 19 20 mHorzntialDistance = a.getDimensionPixelSize( 21 R.styleable.myrectangle_horizontal_distance, 22 getResources().getDimensionPixelSize( 23 R.dimen.myRectangle_horizontal_distance)); 24 mVerticalDIstance = a.getDimensionPixelSize( 25 R.styleable.myrectangle_verticle_distance, 26 getResources().getDimensionPixelSize( 27 R.dimen.myRectangle_verticle_distance)); 28 } finally { 29 a.recycle(); 30 } 31 } 32 33 public MyViewGoup(Context context, AttributeSet attrs, int defStyle) { 34 super(context, attrs, defStyle); 35 } 36 37 @Override 38 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 39 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 40 int width = getPaddingLeft(); 41 int height = getPaddingTop(); 42 /** 43 * 测量子view的大小 44 */ 45 int childrenCount = getChildCount(); 46 int verticleDistance; 47 for (int i = 0; i < childrenCount; i++) { 48 View child = getChildAt(i); 49 measureChild(child, widthMeasureSpec, heightMeasureSpec); 50 /** 51 * 子View设置了自定义属性值就lp中verticleDistance就会获取到值 52 */ 53 LayoutParams lp = (LayoutParams) child.getLayoutParams(); 54 width = getPaddingLeft() + mHorzntialDistance * i; 55 lp.x = width; 56 lp.y = height; 57 verticleDistance = mVerticalDIstance; 58 59 if (lp.verticleDistance > 0) { 60 verticleDistance += lp.verticleDistance; 61 } 62 width += child.getMeasuredWidth(); 63 height += verticleDistance; 64 } 65 /** 66 * 给ViewGroup设置大小. /** 因为设计者可以通过调用setMeasuredDimension决定视图的最终大小 67 * ,例如调用setMeasuredDimension 68 * (100,100)将视图的mMeasuredWidth和mMeasuredHeight设置为100 69 * ,100,那么父视图提供的大小以及程序员在xml中设置的layout_width和layout_height将完全不起作用 70 * ,当然良好的设计一般会根据子视图的measureSpec来设置mMeasuredWidth和mMeasuredHeight的大小 71 */ 72 width += getPaddingRight(); 73 height += getChildAt(getChildCount() - 1).getMeasuredHeight() 74 + getPaddingBottom(); 75 76 if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { 77 System.out.println("是AT_MOST,AT_MOST,AT_MOSTAT_MOSTAT_MOSTAT_MOST"); 78 } 79 80 /** 81 * resolveSize的源码 82 * public static int resolveSize(int size, int measureSpec) { 83 int result = size; 84 int specMode = MeasureSpec.getMode(measureSpec); 85 int specSize = MeasureSpec.getSize(measureSpec); 86 switch (specMode) { 87 case MeasureSpec.UNSPECIFIED: 88 result = size; 89 break; 90 case MeasureSpec.AT_MOST: 91 result = Math.min(size, specSize); 92 break; 93 case MeasureSpec.EXACTLY: 94 result = specSize; 95 break; 96 } 97 return result; 98 } 99 所以不管怎么谁知其实都是屏幕的大小,这widthMeasureSpec的mode类型是EXACTLY100 */101 setMeasuredDimension(resolveSize(width, widthMeasureSpec),102 resolveSize(height, heightMeasureSpec));103 }104 105 @Override106 protected void onLayout(boolean changed, int l, int t, int r, int b) {107 108 /**109 * 给子View设置位置(其实感觉是指定一块区域)110 */111 112 int childrenCount = getChildCount();113 for (int i = 0; i < childrenCount; i++) {114 View child = getChildAt(i);115 LayoutParams lp = (LayoutParams) child.getLayoutParams();116 child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y117 + child.getMeasuredHeight());118 119 }120 121 }122 123 @Override124 protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {125 return p instanceof LayoutParams;126 }127 128 @Override129 protected LayoutParams generateDefaultLayoutParams() {130 return new LayoutParams(LayoutParams.WRAP_CONTENT,131 LayoutParams.WRAP_CONTENT);132 }133 134 @Override135 public LayoutParams generateLayoutParams(AttributeSet attrs) {136 return new LayoutParams(getContext(), attrs);137 }138 139 @Override140 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {141 return new LayoutParams(p.width, p.height);142 }143 144 private class LayoutParams extends ViewGroup.LayoutParams {145 146 int x;147 int y;148 public int verticleDistance;149 150 public LayoutParams(Context context, AttributeSet attrs) {151 super(context, attrs);152 153 TypedArray a = context.obtainStyledAttributes(attrs,154 R.styleable.MyLayoutParams);155 try {156 /**157 * 获取子View设置的竖直偏移量158 */159 verticleDistance = a160 .getDimensionPixelSize(161 R.styleable.MyLayoutParams_layout_verticle_distance,162 -1);163 } finally {164 a.recycle();165 }166 167 }168 169 public LayoutParams(int x, int y) {170 super(x, y);171 }172 173 public LayoutParams(android.view.ViewGroup.LayoutParams arg0) {174 super(arg0);175 }176 177 }178 179 }
4)activity_main.xml
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 xmlns:myrectangle="http://schemas.android.com/apk/res/com.example.myviewgroup" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 tools:context=".MainActivity" > 7 8 <com.example.myviewgroup.view.MyViewGoup 9 android:layout_width="match_parent"10 android:layout_height="match_parent"11 android:background="#FF00FF"12 myrectangle:horizontal_distance="70dp"13 myrectangle:verticle_distance="50dp" >14 15 <View16 android:layout_width="100dp"17 android:layout_height="150dp"18 android:background="#FF0000" />19 20 <View21 android:layout_width="100dp"22 android:layout_height="150dp"23 android:background="#00FF00" />24 25 <View26 android:layout_width="100dp"27 android:layout_height="150dp"28 android:background="#0000FF" />29 </com.example.myviewgroup.view.MyViewGoup>30 31 </LinearLayout>
HackThree
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。