本来我是不准备写这篇文章的,我实在想不出有什么样奇怪的理由,会去继承ViewGroup然后自定义一个布局,大概是我的项目经验还不够吧,想了好久,想到了这样一个需求:

需求


如图:在项目中经常有一个这样的需求,一个View靠左,另一个View靠右,这样的布局方式使用频率非常高,通常使用的是RelativeLayout,但是每次设置Align属性真的好烦,现在就来实现一下这样的布局,解决这个问题。

思路

其实具体实现一个布局,还是可以分为两种:
1.继承一个具体的Layout,这样可以省去很多的代码逻辑,只需要注意自己要处理的业务即可,就比如说Listview嵌套Listview到时候,我们会考虑重写它的onMeasure方法。
2.继承自ViewGroup,然后自己设计代码逻辑。

LayoutParams

之前在介绍onMeasure的时候,我们注意到一个特殊的类MeasureSpec,那onLayout中,我们要注意什么参数呢?答案是:LayoutParams,这个单词直译是布局参数,从名字就可以看出是和布局相关的,既然说onLayout是用于确定子View位置的方法,那么自然离不开它的使用。

LayoutParams用于确定支持childView支持哪些属性,比如LinearLayout有一个LinearLayout.LayoutParams,这个LayoutParams就提供了Gravity,Weight这两个属性。而下面这段代码,用到了MarginLayoutParams它为子View提供了Margin属性。

源码:

这里使用第二种方式实现,也就是直接继承ViewGroup,因为我的需求是一个布局,它只允许有两个子View,一个在左边,一个在右边,这个不同于其它任何一个布局。

/**
* 自定义布局
* Created by ChenSS on 2016/12/3.
*/
public class MyRelativeLayout extends ViewGroup {
public MyRelativeLayout(Context context) {
this(context, null);
} public MyRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
} public MyRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
} @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
int childWidth;
int childHeight;
MarginLayoutParams params; for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
childWidth = childView.getMeasuredWidth();
childHeight = childView.getMeasuredHeight();
params = (MarginLayoutParams) childView.getLayoutParams(); int left = 0, top = 0, right = 0, bottom = 0; switch (i) {
case 0:
left = params.leftMargin;
top = params.topMargin;
break;
case 1:
left = getWidth() - childWidth - params.rightMargin;
top = params.topMargin;
break;
}
right = left + childWidth;
bottom = childHeight + top;
childView.layout(left, top, right, bottom);
}
} @Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
//指定我们所需的LayoutParams
return new MarginLayoutParams(getContext(), attrs);
} @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); // 计算出所有的childView的宽和高
measureChildren(widthMeasureSpec, heightMeasureSpec); // wrap_content时设置的宽和高
int width = 0;
int height = 0; int childCount = getChildCount();
if (childCount > 2)
throw new IllegalArgumentException("too many childView"); int childWidth;
int childHeight;
MarginLayoutParams params;
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
params = (MarginLayoutParams) childView.getLayoutParams(); //宽度为子View大小总和
childWidth = childView.getMeasuredWidth() + params.leftMargin + params.rightMargin;
width += childWidth; //高度取最高的那个子View
childHeight = childView.getMeasuredHeight() + params.topMargin + params.bottomMargin;
height = childHeight > height ? childHeight : height;
} /**
* 根据MeasureSpec设置MyRelativeLayout的宽高
*/
setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width,
(heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height);
}
}

参考:Android 手把手教您自定义ViewGroup

等到什么时候有个好的创意,再改成原创o(∩_∩)o~

安卓自定义控件(四)实现自定义Layout的更多相关文章

  1. 安卓自定义控件(三)实现自定义View

    前面两篇博客,把View绘制的方法说了一下,但是,我们只在onDraw里面做文章,控件都是直接传入一个Context,还不能在布局文件里使用自定义View.这一篇博客,就不再讲绘制,在我们原先的基础上 ...

  2. 安卓自定义控件(一)Canvas、Paint、Shader、Xfermode

    关于自定义控件,之前就写过一篇自定义控件,上图下字的Button,图片任意指定大小,但是使用效果还是让人感觉不幸福,这次索性彻彻底底地对自定义控件做一次彻彻底底的总结. 我会花4篇博客来介绍自定义控件 ...

  3. 安卓第四天笔记-Sqlite

    安卓第四天笔记-Sqlite 1.数据库的创建运行与更新 1.1.创建一个类继承SqliteOpenHelper 1.2.创建构造方法 /** * 数据库创建类 * @author 刘楠 * * 20 ...

  4. 安卓自定义控件(二)BitmapShader、ShapeDrawable、Shape

    第一篇博客中,我已经Canvas.Paint.Shader.Xfermode这些对象做了总结,而现在这篇文章主要介绍BitmapShader位图渲染,Xfermode如何实际应用,还有形状的绘制.不过 ...

  5. MATLAB地图工具箱学习总结(四)自定义投影

    MATLAB地图工具箱学习总结(四)自定义投影 这是本系列的最后一篇文章,准备给大家讲讲自定义投影怎么做.在做这项作业的时候,自己也是花了不少时间,将所有地图投影源文件都看了一遍,简单分析了一下源代码 ...

  6. 微信公众账号开发教程(四)自定义菜单(含实例源码)——转自http://www.cnblogs.com/yank/p/3418194.html

    微信公众账号开发教程(四)自定义菜单 请尊重作者版权,如需转载,请标明出处. 应大家强烈要求,将自定义菜单功能课程提前. 一.概述: 如果只有输入框,可能太简单,感觉像命令行.自定义菜单,给我们提供了 ...

  7. NGUI系列教程四(自定义Atlas,Font)

    今天我们来看一下怎么自定义NGUIAtlas,制作属于自己风格的UI.第一部分:自定义 Atlas1 . 首先我们要准备一些图标素材,也就是我们的UI素材,将其导入到unity工程中.2. 全选我们需 ...

  8. Wix打包系列(四) 自定义UI

    原文:Wix打包系列(四) 自定义UI 除了标准的安装界面,如果我们要在安装时需要提供一些额外的信息时,这时就需要自定义界面来显示和录入这些信息. 4.1  自定义对话框 如上一章中我们测试数据库的连 ...

  9. UICollectionView之自定义Layout

    #import <UIKit/UIKit.h> @interface WQViewController : UIViewController - (id)initWithFrame:(CG ...

  10. 自定义 Layout布局 UICollectionViewLayout

    from:   http://www.tuicool.com/articles/vuyIriN 当我们使用系统自带的UICollectionViewFlowLayout无法实现我们的布局时,我们就可以 ...

随机推荐

  1. 理解HTTPS

    总结HTTPS HTTPS要使客户端与服务器端的通信过程得到安全保证,必须使用的对称加密算法,但是协商对称加密算法的过程,需要使用非对称加密算法来保证安全,然而直接使用非对称加密的过程本身也不安全, ...

  2. Emgu.CV(一)

    由于这块的知识不少,会分好几期写完 什么是OpenCV? OpenCV是一个基于(开源)发行的跨平台计算机视觉库,可以运行在Linux.Windows和Mac OS操作系统上.它轻量级而且高效--由一 ...

  3. 真正从0开始用Unity3D制作类战地2玩法的类龙之谷、王者荣耀的手游(暨全平台游戏)

    如题,(从2017年10月18日开始)正在利用业余时间研发一款神泣Shaiya2手游,引擎用Unity3D. 原因主要有2点: 对神泣太多感情,希望能做点什么来纪念乃至留下神泣这款网游: 时机已到,是 ...

  4. zabbix杂文

    ps:这是从我原来记录的地方直接copy的,很杂乱,不过主要我想记录当时的思路,乱就乱了...... 背景: 这是进公司的第一个正式任务(之前在测试环境熟悉),所以基本上最近一段时间都在弄这个东西,一 ...

  5. 如何设置App的启动图

    如何设置App的启动图,也就是Launch Image? Step1 1.点击Image.xcassets 进入图片管理,然后右击,弹出"New Launch Image" 2.如 ...

  6. Java基础总结--泛型总结

    -----泛型------JDK1.5出现的机制1.泛型出现的原因--简化书写,提高安全性技术的由来是为了解决问题,现在存在该问题,所有的容器定义类型为Object,所以任何对 象均可以放入容器--进 ...

  7. 启动报错 Unsupported major.minor version 51.0

    Unsupported major.minor version 51.0错误, 是使用jdk6启动jdk7编译的项目,更换jdk7就好了,或者用jdk6重新打包项目. 解决起来也很方便:打开excli ...

  8. 用Unity3d做游戏(一)

    准备工作: vs2013,直接从官网下载或者这里 http://pan.baidu.com/s/1bFxC54   unity3d,从官网下载,版本4或者5 https://unity3d.com/c ...

  9. Windows环境下多线程编程原理与应用读书笔记(3)————Windows环境中的多线程实现(3)

    纤程 纤程(fiber): 相当于用户级别的线程或轻进程.纤程由Win32库函数支持,对核心是不可见的.纤程可以通过SwitchToFiber显示至另一合作纤程,以实现合作纤程之间的协同.线程是在Wi ...

  10. poj 3340 Barbara Bennett's Wild Numbers(数位DP)

    Barbara Bennett's Wild Numbers Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3153   A ...