Android标签布局LaybelLayout
来源:互联网 发布:网上开个淘宝店流程图 编辑:程序博客网 时间:2024/05/20 07:37
项目请参考 LaybelLayout
在开发当中,我们或多或少的可能会用到一种类似于标签一样的布局,如下图所示。
在SDK自带的控件当中,我们很难实现这样一种效果。如果根据显示内容使用LinearLayout
去动态生成的化,又显得很繁琐,而且很难移植到别的项目里去。于是就实现了这么一个布局Layout.
大致思路
一,子控件的测量和摆放
首先我们是直接继承了ViewGroup
.众所周知,要自定义一个布局,必须要重写ViewGroup
的onLayout()
方法,在这个方法里面,对子控件进行布局的摆放。但是在摆放前,咱们得先给这些子控件进行一个测量,知道它们自己需要多大空间。所以在onMeasure()
方法里面,对这些子控件进行测量。因为要支持margin
外边界吧,所以ViewGroup
最原始的那个LayoutParams
就不能使用啦,咱们得用MarginLayoutParams
。下面给出测量思路:
1,先说说宽度问题,测出每个子控件的宽度,然后每个控件占的宽度是 自身宽度 + margin_left + margin_right.
2,每一行的高度就等于 自身高度 + margin_top + margin_bottom + line_padding × 2,其中 ‘line_padding’ 是我定义的一个属性
3,测量时候,如果发现有控件占领宽度加上LaybelLayout
自padding
大于了LaybelLayout
的宽度,则让它刚好等于 LaybelLayout宽度 - 左右padding
4,测量完成之后,遍历子控件,并且将它们的摆放信息存到ChildLayoutMsg
这个内部类里面,这样在待会onLayout()
里面只需要将信息提取出来,进行摆放就可以了。
5,记录摆放的信息,也就是记录每个子控件的left, top, right, bottom
.也是根据每一行的剩余宽度来判断,如果控件占的宽度加上父控件的padding大于了剩余宽度,则需要摆放到下一行二,LaybelLayout本身的宽高配置
因为要实现wrap_content
属性,这就需要得到本控件的最小宽高。需要知道最小宽度,则需要只知道LaybelLayout的父控件给LaybelLayout分配了多大空间。!= = 这就需要用MeasureSpec
把本控件的宽高的mode
取出,不知道mode干嘛用的请自行google
如果mode是EXACTLY
,也就是LaybelLayout的父控件给定了宽度,这种情况就用默认的super.onMeasure(widthMeasureSpec, heightMeasureSpec)
进行设置宽高就行了。现在主要应对不确定宽度的情况,也就是判断宽和高的mode不等于EXACTLY
,把最小宽高通过setMeasuredDimension()
设置进去。这里还有个问题,当最小宽高超过了LaybelLayout的父控件给的最大限度时,咋办呢,是不是又要去判断下?其实有个api帮我们实现了这个功能,我们只需要将最小宽高放进去,就会返回一个合适的宽高回来,就是使用resolveSize()
了。
下面来看看resolveSize()
都干了什么
public static int resolveSize(int size, int measureSpec) { return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK;}
发现它调用了resolveSizeAndState()
,于是跟进去看看
public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { final int specMode = MeasureSpec.getMode(measureSpec); final int specSize = MeasureSpec.getSize(measureSpec); final int result; switch (specMode) { case MeasureSpec.AT_MOST: if (specSize < size) { result = specSize | MEASURED_STATE_TOO_SMALL; } else { result = size; } break; case MeasureSpec.EXACTLY: result = specSize; break; case MeasureSpec.UNSPECIFIED: default: result = size; } return result | (childMeasuredState & MEASURED_STATE_MASK);}
第三个参数先不用管,这里用宽度来说明,传入了最小宽度和测量宽度的Spec。记住,这个最小宽度是与LaybelLayout的测量宽度有关的,把每一行的宽度进行比较,取最大的那个宽度作为本控件的最小宽度。虽然在本控件里面,最小宽度的计算方式已经处理了这个问题,但是任然用这个函数来包裹一层。可以看到,如果是父控件给定了确定宽度EXACTLY
,则完全按照测量的宽度来作为本控件的宽度;如果父控件对本控件没有加以限制UNSPECIFIED
,表示我这个控件需要多大,就得多大,大小完全自己决定,于是返回我传入的size(最小宽度);如果父控件给定了个范围AT_MOST
,则判断下,测量值和传入的size哪个小,就返回哪个,这样的好处就是,绝对不会超出父控件的范围。
总结
上面讲得确实有点啰嗦,但是为了力求准确,也只好这样了。如有错误,请各位看客指出,在下感激不尽。具体源码和Demo,请前往 github
- Android标签布局LaybelLayout
- Android标签布局
- Android帧布局<TabHost>标签
- android布局标签<include />使用
- android布局学习--标签属性
- Android布局演示之底部标签栏
- android布局文件 merge 标签的使用
- android布局文件 merge 标签的使用
- Android layout 布局属性 xml 标签 详情
- Android布局属性讲解标签属性
- Android-Layout 布局属性 & 参数标签 集合
- Android 布局中的include标签使用
- Android layout布局属性、标签属性
- Android 流式布局-动态标签实现
- android布局文件 merge 标签的使用
- android流式布局--流式标签
- Android布局优化之merge标签
- android 布局优化标签<include/>、<merge />、<ViewStub />
- Spring Batch 之 Sample(固定长格式文件读写)(六)
- Oracle各版本下载地址
- 从TCP三次握手说起——浅析TCP协议中的疑难杂症
- 6 - leetcode ZigZag Conversion
- EventBus3.0的使用
- Android标签布局LaybelLayout
- python设计的最简单小程序-学习笔记5-计算饭费
- mark---android touchpanel详解
- Spring Batch 之 Sample(复合格式文件的读、多文件的写)(七)
- 两个有序数组合并为一个有序数组
- red hat 两台Linux服务器间文件传输
- PopupWindowANDWindowManager 浮动窗口和窗口管理
- 关于oracle“ORA-01810格式代码出现两次”的解决方案
- MySQL分区--列分区