自定义ViewGroup(4)等分格子布局
来源:互联网 发布:转帖软件 编辑:程序博客网 时间:2024/06/05 16:48
继承自ViewGroup的自定义等分格子布局容器。
定义等分格子容器重要的步骤有两个,测量确定容器和子控件的宽度和高度由onMeasure方法完成。
摆放步骤有onLayout完成,等分格子布局需要指定列数,并根据容器宽度和列数计算出
格子宽度,再根据容器的高度和子元素需要摆放的行数计算出格子的高度,然后根据计算的结果,
在onLayout中摆放子控件。
第一步,定义容器的两个属性:子元素列数和元素之间的间隔
<declare-styleable name="CustomViewGroupGridLayout"><attr name="numColumns" format="integer" /><attr name="itemMargin" format="integer" /></declare-styleable>
第二步,在布局文件中添加容器
<com.twelve.custom.CustomViewGroupGridLayoutandroid:id="@+id/list"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#1e1d1d"android:orientation="vertical"app:itemMargin="1"app:numColumns="4" ></com.twelve.custom.CustomViewGroupGridLayout>注意,要在布局文件头部添加引用
xmlns:app="http://schemas.android.com/apk/res-auto"
第三步,初始化容器类CustomViewGroupGridLayout,获取自定义的属性值
/** * 构造方法:获取自定义属性值 * :View对象之间的距离 * :View对象列数 * @param context 上下文 * @param attrs 属性容器 * @param defStyle 未知 */public CustomViewGroupGridLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);if (attrs != null) { /** * 获取自定义属性列表 */TypedArray a = getContext().obtainStyledAttributes(attrs,R.styleable.CustomViewGroupGridLayout); int n = a.length(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomViewGroupGridLayout_numColumns: /** * 获取给定的列数,默认值为2 */ mIntColumns = a.getInteger(R.styleable.CustomViewGroupGridLayout_numColumns, 2); break; case R.styleable.CustomViewGroupGridLayout_itemMargin: /** * 获取指定的距离,默认值为2 */ mIntMargin = a.getInteger(R.styleable.CustomViewGroupGridLayout_itemMargin, 2); break; } }}}public CustomViewGroupGridLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CustomViewGroupGridLayout(Context context) {this(context, null);}第四步,设置子元素
/** * 从给定的View携带工具中提取View对象 * */public void setGridChildViewContainer(GridChildViewContainer container) {this.mGridChildViewContainer = container; /** * 提取View对象 */int size = container.getCount();for (int i = 0; i < size; i++) {addView(container.getView(i));}}自定义一个GridChildViewContainer类,他负责携带一个View列表,通过getView(1)获取相对应的列表元素,添加到ViewGroup中。
第五步,测量和设置子元素高度和宽度,并获取容器的大小
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { /** * 获取ChildView的measureMode */ int childModeWidth = 0, childModeHeight = 0; if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) childModeWidth = MeasureSpec.UNSPECIFIED; if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.UNSPECIFIED) childModeHeight = MeasureSpec.UNSPECIFIED; /** * 生成子控件的childWidthMeasureSpec和childHeightMeasureSpec * 这两个参数包含measureWidth&measureModeWidth和measureHeight&measureModeHeight * 注意这里的measureWidth和measureHeight初始化值为0,也可以是其他的任意值 */ final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, childModeWidth); final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, childModeHeight); mIntViewCount = getChildCount(); if (mIntViewCount == 0) { super.onMeasure(childWidthMeasureSpec, childHeightMeasureSpec); return; } for (int i = 0; i < mIntViewCount; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } /** * 测量并设置子控件的宽度和高度 */ child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } /** * 设置容器的高度和宽度 */ setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),MeasureSpec.getSize(heightMeasureSpec)); }第六步,根据第五步的测量结果和第三步获取的列数和间隔值,确定子控件的摆放格局。
/** * 这里传入的四个参数l,t,r,b是onMeasure测量的容器的矩形区域 * (l,t)是容器的左上角起点坐标,(r,b)是容器的右下角终点坐标 */@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) { /** * 布局区域高度 */int height = b - t; /** * 布局区域宽度 */int width = r - l; /** * 计算控件摆放需要的行数 */int rows = mIntViewCount % mIntColumns == 0 ? mIntViewCount / mIntColumns : mIntViewCount / mIntColumns + 1;if (mIntViewCount == 0)return; /** * 计算每个格子的宽度:除去间隔之后控件所占的净宽度 */int gridW = (width - mIntMargin * (mIntColumns - 1)) / mIntColumns; /** * 计算每个格子的高度:除去间隔之后控件所占的净高度 */int gridH = (height - mIntMargin * rows) / rows; /** * 开始摆放控件:初始化位置左边顶边界,上面留间隔 */int leftPointer = 0;int topPointer = mIntMargin; /** * 遍历行 */for (int row = 0; row < rows; row++) { /** * 遍历列 */for (int column = 0; column < mIntColumns; column++) { /** * 获取某行某列的子元素 */View child = this.getChildAt(row * mIntColumns + column);if (child == null)return; /** * 左上角起点x坐标leftPointer由列宽gridW列序号和间隔数决定; * 左上角起点y坐标topPointer由行高gridH行序号和间隔数决定, * 在某一行中所有元素都是相同的; */leftPointer = column * gridW + column * mIntMargin; /** * 如果当前布局宽度和测量宽度不一样,就直接用当前布局的宽度重新测量 */if (gridW != child.getMeasuredWidth()|| gridH != child.getMeasuredHeight()) {child.measure(makeMeasureSpec(gridW, EXACTLY),makeMeasureSpec(gridH, EXACTLY));} /** * 摆放子控件 */child.layout(leftPointer, topPointer, leftPointer + gridW, topPointer + gridH);} /** * 一行遍历结束,行起点y坐标下移 */topPointer += gridH + mIntMargin;}}
0 0
- 自定义ViewGroup(4)等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- 自定义ViewGroup (滚动布局)
- ViewGroup自定义布局(左上右下)
- 自定义ViewGroup(1)--横向布局
- Android自定义布局:ViewGroup
- 自定义控件格子布局:CellLayout
- 自定义ViewGroup之流式布局
- 自定义viewGroup打造花式布局
- 自定义viewgroup流式布局
- (安卓) 自定义ViewGroup (自定义ViewGroup的方式实现梯形布局)
- Android自定义ViewGroup(四、打造自己的布局容器)
- android 实现FlowLayout 流线布局(自定义ViewGroup)
- 自定义Viewgroup(2)--可滚动的横向布局
- 自定义viewgroup(5)--可滚动布局,GestureDetector手势监听
- IOS--UILabel 用法详解
- c语言time.h函数库小结
- IOS--颜色转换 数组排序 事件转换
- 虚拟机(Linux系统)共享文件夹
- ios-plist文件读写操作
- 自定义ViewGroup(4)等分格子布局
- 2015年2月——英语
- 山寨版qq源码+素材
- ios-坐标系统(详解UIView的frame、bounds跟center属性[图])
- 【整合篇】Activiti业务与流程的整合
- iOS中定时器NSTimer的使用
- Openlayers手动绘制圆形(v2.13)
- 【自考】运筹学 第四章库存管理
- iPhone编程:UIScrollView的使用方法