视图的绘制仅在Framework层分为三个阶段measure,layout,draw。前一篇博文
《 覆写onMeaure进行measure操作》 关于如何覆写onMeasure, 其目的是为了测量视图的大小也就是第一阶段,如果不了解或者关于onMeasure有什么疑惑可以了解下。 本篇博文是关于如何覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下,才能确定怎么摆放。
一、自定义ViewGroup例子
例子代码 - 纵向显示两个TextView
(1)编写CustomViewGroup
- 1. CustomViewGroup继承自ViewGroup,ViewGroup是所有Layout的父类
- public class CustomViewGroup extends ViewGroup {
- }
2. 覆写View.onMeasure回调函数,用于计算所有child view的宽高,这里偷懒没有进行MeasureSpec模式判断
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- measureChildren(widthMeasureSpec, heightMeasureSpec);
- setMeasuredDimension(widthSize, heightSize);
- }
3. 覆写ViewGroup.onLayout回调函数,用于指定所有child View的位置
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- int mTotalHeight = 0;
- // 遍历所有子视图
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View childView = getChildAt(i);
- // 获取在onMeasure中计算的视图尺寸
- int measureHeight = childView.getMeasuredHeight();
- int measuredWidth = childView.getMeasuredWidth();
- childView.layout(left, mTotalHeight, measuredWidth, mTotalHeight + measureHeight);
- mTotalHeight += measureHeight;
- Log.e(TAG, "changed = " + changed
- + ", left = " + left + ", top = " + top
- + ", right = " + right + ", bottom = " + bottom
- + ", measureWidth = " + measuredWidth + ", measureHieght = " + measureHeight);
- }
- }
3.1 onLayout回调函数参数:
left, top, right, bottom是当前ViewGroup整个在屏幕上的位置,手机屏幕是480 * 800 ,其中高度去除状态栏和title大概724
如果页面只有此ViewGroup则个参数的值
left = 0, top = 0, right = 480, bottom = 724
在此ViewGroup的上面放置一个TextView当期回调的参数值
left = 0, top =
25, right = 480, bottom = 724
3.2 child.layout如何填写参数
View是一个矩形,right和bottom也可以通过以下计算获得,其中Width 和 Height由onMeasure最终设置和决定
right = left + width
bottom = top + height
right = left + width
bottom = top + height
(2)创建Activity
- public class CustomViewGroupActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- CustomViewGroup customViewGroup = new CustomViewGroup(this);
- customViewGroup.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- // 添加子视图
- TextView textViewOne = new TextView(this);
- textViewOne.setText("a child view");
- textViewOne.setBackgroundColor(Color.BLUE);
- textViewOne.setLayoutParams(new LayoutParams(130, 130));
- customViewGroup.addView(textViewOne);
- TextView textViewTwo = new TextView(this);
- textViewTwo.setText("b child view");
- textViewTwo.setBackgroundColor(Color.RED);
- textViewTwo.setLayoutParams(new LayoutParams(80, 80));
- customViewGroup.addView(textViewTwo);
- setContentView(customViewGroup);
- }
- }
二、 疑问
代码添加view和布局中添加view的区别?
1. 代码中添加 ViewGroup
- CustomViewGroup customViewGroup = new CustomViewGroup(this);
- customViewGroup.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- // 添加子视图
- TextView textViewOne = new TextView(this);
- textViewOne.setText("a child view");
- textViewOne.setBackgroundColor(Color.BLUE);
- textViewOne.setLayoutParams(new LayoutParams(130, 130));
- customViewGroup.addView(textViewOne);
- TextView textViewTwo = new TextView(this);
- textViewTwo.setText("b child view");
- textViewTwo.setBackgroundColor(Color.RED);
- textViewTwo.setLayoutParams(new LayoutParams(80, 80));
- customViewGroup.addView(textViewTwo);
- setContentView(customViewGroup);
onLayout输出信息:
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 130, measureHieght = 130
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 80, measureHieght = 80
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 130, measureHieght = 130
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 80, measureHieght = 80
2. xml中配置添加ViewGroup
- <? xml version = "1.0" encoding = "utf-8" ?>
- < com.androiddemo.CustomViewGroup xmlns:android =
- "http://schemas.android.com/apk/res/android"
- android:id = "@+id/custom_viewgroup"
- android:layout_width = "fill_parent"
- android:layout_height = "wrap_content" >
- < TextView
- android:layout_width = "130dip"
- android:layout_height = "130dip"
- android:background = "@color/blue"
- android:text = "@string/first_childview_name" />
- < TextView
- android:layout_width = "80dip"
- android:layout_height = "80dip"
- android:background = "@color/red"
- android:text = "@string/second_childview_name" />
- </ com.androiddemo.CustomViewGroup >
onLayout输出信息:? Width和 Height并不是TextView中设置的固定值
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 195, measureHieght = 195
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 120, measureHieght = 120
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 195, measureHieght = 195
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 120, measureHieght = 120
三 、扩展
× 三个方法的区别?后这个方法最终还是调用第一个方法
- childView.measure(widthMeasureSpec, heightMeasureSpec);
- measureChild(childView, widthMeasureSpec, heightMeasureSpec);
- measureChildren(widthMeasureSpec, heightMeasureSpec);
× 哪些视图属性影响
measure? padding、margin
× 哪些视图属性 影响 layout?
gravity
× view的上下左右和measurespec width和height的关系 ?
四、资料
Android官方文档:
Layouts
细说view流程上
细说view流程下
2013-03-31 更新与onMeasure关联博文
一、自定义ViewGroup例子
例子代码 - 纵向显示两个TextView
(1)编写CustomViewGroup
- 1. CustomViewGroup继承自ViewGroup,ViewGroup是所有Layout的父类
- public class CustomViewGroup extends ViewGroup {
- }
2. 覆写View.onMeasure回调函数,用于计算所有child view的宽高,这里偷懒没有进行MeasureSpec模式判断
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- int heightSize = MeasureSpec.getSize(heightMeasureSpec);
- measureChildren(widthMeasureSpec, heightMeasureSpec);
- setMeasuredDimension(widthSize, heightSize);
- }
3. 覆写ViewGroup.onLayout回调函数,用于指定所有child View的位置
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- int mTotalHeight = 0;
- // 遍历所有子视图
- int childCount = getChildCount();
- for (int i = 0; i < childCount; i++) {
- View childView = getChildAt(i);
- // 获取在onMeasure中计算的视图尺寸
- int measureHeight = childView.getMeasuredHeight();
- int measuredWidth = childView.getMeasuredWidth();
- childView.layout(left, mTotalHeight, measuredWidth, mTotalHeight + measureHeight);
- mTotalHeight += measureHeight;
- Log.e(TAG, "changed = " + changed
- + ", left = " + left + ", top = " + top
- + ", right = " + right + ", bottom = " + bottom
- + ", measureWidth = " + measuredWidth + ", measureHieght = " + measureHeight);
- }
- }
3.1 onLayout回调函数参数:
left, top, right, bottom是当前ViewGroup整个在屏幕上的位置,手机屏幕是480 * 800 ,其中高度去除状态栏和title大概724
如果页面只有此ViewGroup则个参数的值
left = 0, top = 0, right = 480, bottom = 724
在此ViewGroup的上面放置一个TextView当期回调的参数值
left = 0, top =
25, right = 480, bottom = 724
3.2 child.layout如何填写参数
View是一个矩形,right和bottom也可以通过以下计算获得,其中Width 和 Height由onMeasure最终设置和决定
right = left + width
bottom = top + height
right = left + width
bottom = top + height
(2)创建Activity
- public class CustomViewGroupActivity extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- CustomViewGroup customViewGroup = new CustomViewGroup(this);
- customViewGroup.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- // 添加子视图
- TextView textViewOne = new TextView(this);
- textViewOne.setText("a child view");
- textViewOne.setBackgroundColor(Color.BLUE);
- textViewOne.setLayoutParams(new LayoutParams(130, 130));
- customViewGroup.addView(textViewOne);
- TextView textViewTwo = new TextView(this);
- textViewTwo.setText("b child view");
- textViewTwo.setBackgroundColor(Color.RED);
- textViewTwo.setLayoutParams(new LayoutParams(80, 80));
- customViewGroup.addView(textViewTwo);
- setContentView(customViewGroup);
- }
- }
二、 疑问
代码添加view和布局中添加view的区别?
1. 代码中添加 ViewGroup
- CustomViewGroup customViewGroup = new CustomViewGroup(this);
- customViewGroup.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
- // 添加子视图
- TextView textViewOne = new TextView(this);
- textViewOne.setText("a child view");
- textViewOne.setBackgroundColor(Color.BLUE);
- textViewOne.setLayoutParams(new LayoutParams(130, 130));
- customViewGroup.addView(textViewOne);
- TextView textViewTwo = new TextView(this);
- textViewTwo.setText("b child view");
- textViewTwo.setBackgroundColor(Color.RED);
- textViewTwo.setLayoutParams(new LayoutParams(80, 80));
- customViewGroup.addView(textViewTwo);
- setContentView(customViewGroup);
onLayout输出信息:
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 130, measureHieght = 130
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 80, measureHieght = 80
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 130, measureHieght = 130
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 80, measureHieght = 80
2. xml中配置添加ViewGroup
- <? xml version = "1.0" encoding = "utf-8" ?>
- < com.androiddemo.CustomViewGroup xmlns:android =
- "http://schemas.android.com/apk/res/android"
- android:id = "@+id/custom_viewgroup"
- android:layout_width = "fill_parent"
- android:layout_height = "wrap_content" >
- < TextView
- android:layout_width = "130dip"
- android:layout_height = "130dip"
- android:background = "@color/blue"
- android:text = "@string/first_childview_name" />
- < TextView
- android:layout_width = "80dip"
- android:layout_height = "80dip"
- android:background = "@color/red"
- android:text = "@string/second_childview_name" />
- </ com.androiddemo.CustomViewGroup >
onLayout输出信息:? Width和 Height并不是TextView中设置的固定值
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 195, measureHieght = 195
- changed = true, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 120, measureHieght = 120
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 195, measureHieght = 195
- changed = false, left = 0, top = 0, right = 480, bottom = 724, measureWidth = 120, measureHieght = 120
三 、扩展
× 三个方法的区别?后这个方法最终还是调用第一个方法
- childView.measure(widthMeasureSpec, heightMeasureSpec);
- measureChild(childView, widthMeasureSpec, heightMeasureSpec);
- measureChildren(widthMeasureSpec, heightMeasureSpec);
× 哪些视图属性影响
measure? padding、margin
× 哪些视图属性 影响 layout?
gravity
× view的上下左右和measurespec width和height的关系 ?
四、资料
Android官方文档:
Layouts
细说view流程上
细说view流程下
2013-03-31 更新与onMeasure关联博文