3. 支持layout_margin属性

如果我们自定义的布局参数类继承自MarginLayoutParams,就自动支持了layout_margin属性了,我们需要做的就是直接在布局文件中使用layout_margin属性,然后再onMeasure和onLayout中使用margin属性值测量和摆放子控件。需要注意的是我们测量子控件的时候应该调用measureChildWithMargin()方法。

布局文件:

xmlns:openxu= "http://schemas.android.com/apk/res/com.openxu.costomlayout"

android:background="#33000000"

android:layout_width= "match_parent"

android:layout_height= "match_parent" >

android:layout_width= "wrap_content"

android:layout_height= "wrap_content"

openxu:layout_position= "left"

android:layout_marginLeft = "20dip"

android:background= "#FF8247"

android:textColor= "#ffffff"

android:textSize="20dip"

android:padding= "20dip"

android:text="按钮1" />

android:layout_width= "wrap_content"

android:layout_height= "wrap_content"

android:layout_marginTop = "30dip"

openxu:layout_position= "right"

android:background= "#8B0A50"

android:textColor= "#ffffff"

android:textSize="18dip"

android:padding= "10dip"

android:text="按钮2222222222222" />

android:layout_width= "wrap_content"

android:layout_height= "wrap_content"

android:layout_marginLeft = "30dip"

android:layout_marginBottom = "10dip"

openxu:layout_position= "bottom"

android:background= "#7CFC00"

android:textColor= "#ffffff"

android:textSize="20dip"

android:padding= "15dip"

android:text="按钮333333" />

android:layout_width= "wrap_content"

android:layout_height= "wrap_content"

openxu:layout_position= "rightAndBottom"

android:layout_marginBottom = "30dip"

android:background= "#1E90FF"

android:textColor= "#ffffff"

android:textSize="15dip"

android:padding= "10dip"

android:text="按钮4" />

android:layout_width= "wrap_content"

android:layout_height= "wrap_content"

openxu:layout_position= "center"

android:layout_marginBottom = "30dip"

android:layout_marginRight = "30dip"

android:background= "#191970"

android:textColor= "#ffffff"

android:textSize="20dip"

android:padding= "15dip"

android:text="按钮5" />

onMeasure和onLayout:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式

int widthMode = MeasureSpec. getMode(widthMeasureSpec);

int heightMode = MeasureSpec. getMode(heightMeasureSpec);

int sizeWidth = MeasureSpec. getSize(widthMeasureSpec);

int sizeHeight = MeasureSpec. getSize(heightMeasureSpec);

int layoutWidth = 0;

int layoutHeight = 0;

int cWidth = 0;

int cHeight = 0;

int count = getChildCount();

// 计算出所有的childView的宽和高

for( int i = 0; i < count; i++){

View child = getChildAt(i);

measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);

}

CustomLayoutParams params = null;

if(widthMode == MeasureSpec. EXACTLY){

//如果布局容器的宽度模式时确定的(具体的size或者match_parent)

layoutWidth = sizeWidth;

} else{

//如果是未指定或者wrap_content,我们都按照包裹内容做,宽度方向上只需要拿到所有子控件中宽度做大的作为布局宽度

for ( int i = 0; i < count; i++) {

View child = getChildAt(i);

cWidth = child.getMeasuredWidth();

params = (CustomLayoutParams) child.getLayoutParams();

//获取子控件宽度和左右边距之和,作为这个控件需要占据的宽度

int marginWidth = cWidth+params.leftMargin+params.rightMargin ;

layoutWidth = marginWidth > layoutWidth ? marginWidth : layoutWidth;

}

}

//高度很宽度处理思想一样

if(heightMode == MeasureSpec. EXACTLY){

layoutHeight = sizeHeight;

} else{

for ( int i = 0; i < count; i++) {

View child = getChildAt(i);

cHeight = child.getMeasuredHeight();

params = (CustomLayoutParams) child.getLayoutParams();

int marginHeight = cHeight+params.topMargin+params.bottomMargin ;

layoutHeight = marginHeight > layoutHeight ? marginHeight : layoutHeight;

}

}

// 测量并保存layout的宽高

setMeasuredDimension(layoutWidth, layoutHeight);

}

@Override

protected void onLayout( boolean changed, int left, int top, int right,

int bottom) {

final int count = getChildCount();

int childMeasureWidth = 0;

int childMeasureHeight = 0;

CustomLayoutParams params = null;

for ( int i = 0; i < count; i++) {

View child = getChildAt(i);

// 注意此处不能使用getWidth和getHeight,这两个方法必须在onLayout执行完,才能正确获取宽高

childMeasureWidth = child.getMeasuredWidth();

childMeasureHeight = child.getMeasuredHeight();

params = (CustomLayoutParams) child.getLayoutParams();

switch (params. position) {

case CustomLayoutParams. POSITION_MIDDLE: // 中间

left = (getWidth()-childMeasureWidth)/2 - params.rightMargin + params.leftMargin ;

top = (getHeight()-childMeasureHeight)/2 + params.topMargin - params.bottomMargin ;

break;

case CustomLayoutParams. POSITION_LEFT: // 左上方

left = 0 + params. leftMargin;

top = 0 + params. topMargin;

break;

case CustomLayoutParams. POSITION_RIGHT: // 右上方

left = getWidth()-childMeasureWidth - params.rightMargin;

top = 0 + params. topMargin;

break;

case CustomLayoutParams. POSITION_BOTTOM: // 左下角

left = 0 + params. leftMargin;

top = getHeight()-childMeasureHeight-params.bottomMargin ;

break;

case CustomLayoutParams. POSITION_RIGHTANDBOTTOM:// 右下角

left = getWidth()-childMeasureWidth - params.rightMargin;

top = getHeight()-childMeasureHeight-params.bottomMargin ;

break;

default:

break;

}

// 确定子控件的位置,四个参数分别代表(左上右下)点的坐标值

child.layout(left, top, left+childMeasureWidth, top+childMeasureHeight);

}

}

运行效果:

好了,就写到这里,如果想尝试设置其他属性,比如above、below等,感兴趣的同学可以尝试一下哦~。其实也没什么难的,无非就是如果布局属性定义的多,那么在onMeasure和onLayout中考虑的问题就更多更复杂,自定义布局容器就是根据自己的需求,让容器满足我们特殊的摆放要求。

总结一下今天学习的内容,这篇博客主要学习了两个知识点:

自定义ViewGroup的步骤:

①. 继承ViewGroup,覆盖构造方法

②. 重写onMeasure方法测量子控件和自身宽高

③. 实现onLayout方法摆放子控件

为布局容器自定义布局属性:

①. 大致明确布局容器的需求,初步定义布局属性

②. 继承LayoutParams,定义布局参数类

③. 重写获取布局参数的方法

④. 在布局文件中使用布局属性

⑤. 在onMeasure和onLayout中使用布局参数

android layout_margin的值,Android自定义ViewGroup( 支持layout_margin属性)相关推荐

  1. Android UI设计之十一自定义ViewGroup,打造通用的关闭键盘小控件ImeObser

    2019独角兽企业重金招聘Python工程师标准>>> 转载请注明出处:http://blog.csdn.net/llew2011/article/details/51598682 ...

  2. android edittext hint值,Android EditText Hint Size

    可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试): 问题: How to reduce EditText Hint size? 回答1: You can ...

  3. android fragment返回值,android – PreferenceFragment :: onPreferenceTreeClick返回值 – 它做什么?...

    调用它的代码在 Preference#performClick(PreferenceScreen preferenceScreen)中,它执行以下操作: PreferenceManager prefe ...

  4. android 自定义图片容器,Android应用开发中自定义ViewGroup视图容器的教程

    一.概述在写代码之前,我必须得问几个问题: 1.ViewGroup的职责是啥?ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性, ...

  5. Android开发实践:自定义ViewGroup的onLayout()分析

    Android开发中,对于自定义View,分为两种,一种是自定义控件(继承View类),另一种是自定义布局容器(继承ViewGroup).如果是自定义控件,则一般需要重载两个方法,一个是onMeasu ...

  6. 自定义ViewGroup中onMeasure()的来龙去脉

    目录 1.引言 2.谁来调用onMeasure()? 3.widthMeasureSpec和heightMeasureSpec 4.wrap_content之谜 5.总结 1.引言 刚入职不满一年的A ...

  7. Android自定义ViewGroup的OnMeasure和onLayout详解

    前一篇文章主要讲了自定义View为什么要重载onMeasure()方法http://blog.csdn.net/tuke_tuke/article/details/73302595 那么,自定义Vie ...

  8. Android 自定义ViewGroup 实战篇 - 实现FlowLayout

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38352503 ,本文出自[张鸿洋的博客] 1.概述 上一篇已经基本给大家介绍了如 ...

  9. Android 手把手教您自定义ViewGroup

    最近由于工作的变动,导致的博客的更新计划有点被打乱,希望可以尽快脉动回来~ 今天给大家带来一篇自定义ViewGroup的教程,说白了,就是教大家如何自定义ViewGroup,如果你对自定义ViewGr ...

最新文章

  1. 如何去遍历对象中的所有的属性值
  2. 动态代理(JDK的动态代理)
  3. 一个响应ping包延迟偏大的问题
  4. 以太网性能测试分析仪
  5. linux内核的I2C子系统详解5——i2c_driver的注册、i2c_client的来源
  6. 【视频教程】JEECG 入门视频教程
  7. Robust Principal Component Analysis?(PCP)
  8. dmol3给定关键字不在字典中_一日一技:举例说明python中的map()方法
  9. [PhoenixRC模拟器安装]
  10. ascii码表的使用
  11. SQL Server 2008 R2安装
  12. python搞机器视觉,掌控Python 人工智能之机器视觉
  13. 久泰新材料在港上市申请失效:年亏损超2亿元,崔轶钧为董事长
  14. SDL库的安装,spca5xx的安装,spcaview 的安装,摄像头的查看,及常见问题的解决方法。
  15. Pr:抠像与视频合成
  16. 京东数据分析工程师(实习生)笔试
  17. html5悬浮圆圈背景动画特效,html5圆圈浮动背景动画特效
  18. Unity加载优化-将基于LZMA的ab压缩方案修改为LZ4压缩的过程
  19. 走近棒球运动·底特律老虎队·MLB棒球创造营
  20. 乐观型人格分析,性格乐观的优缺点和职业发展分析

热门文章

  1. SyntaxError: Missing parentheses in call to 'print' 这个错误原因是Python版本问题
  2. ubuntu16.0.4安装mysql5.7以及设置远程访问
  3. Ubuntu用户连续N次输入错误密码进行登陆时自动锁定X分钟
  4. E: Sub-process /usr/bin/dpkg returned an error code (1)
  5. 用 1 行 Python 代码实现 FTP 服务器 - Pyftpdlib
  6. 执行Oracle中的sqlldr xxx.ctl命令导入数据时,当错误无法导入时,注意查看「xxx.log信息」
  7. java中的“+”运算符,产生新对象问题。(非常好的面试题!)
  8. 圆弧周长公式_钢板和钢管的理论重量计算公式居然不一样?
  9. 【Python】Python中文编码
  10. 【数据分析】目标优化矩阵表确定权重