* 1 实现3个构造函数
* 2 重写onMeasure 方法,计算子控件和自己的各种尺寸 (必须调用measureChildren)
* 3 调用onLayout方法,对子位置进行计算,进行布局
*
* 重写方法generateLayoutParams返回MarginLayoutParams 因为可以得到控件的margin参数
public class CustomImgContainer extends ViewGroup { private static final String TAG = "CustomImgContainer"; public CustomImgContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public CustomImgContainer(Context context) { super(context); } public CustomImgContainer(Context context, AttributeSet attrs) { super(context, attrs); } /** * 计算所有ChildView的宽度和高度 然后根据ChildView的计算结果,设置自己的宽和高 */ @Override 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); Log.e(TAG, (heightMode == MeasureSpec.UNSPECIFIED) + "," + sizeHeight + "," + getLayoutParams().height); // 计算出所有的childView的宽和高 measureChildren(widthMeasureSpec, heightMeasureSpec); /** * 记录如果是wrap_content是设置的宽和高 */ int width = 0; int height = 0; int cCount = getChildCount();//得到子容器的数量 int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; // 用于计算左边两个childView的高度 int lHeight = 0; // 用于计算右边两个childView的高度,最终高度取二者之间大值 int rHeight = 0; // 用于计算上边两个childView的宽度 int tWidth = 0; // 用于计算下面两个childiew的宽度,最终宽度取二者之间大值 int bWidth = 0; /** * 根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); // 上面两个childView 的两个宽度+总的Margin(下面相同) if (i == 0 || i == 1) { tWidth += cWidth + cParams.leftMargin + cParams.rightMargin; } if (i == 2 || i == 3)//下面两个childView { bWidth += cWidth + cParams.leftMargin + cParams.rightMargin; } //左边两个 if (i == 0 || i == 2) { lHeight += cHeight + cParams.topMargin + cParams.bottomMargin; } //右边两个 if (i == 1 || i == 3) { rHeight += cHeight + cParams.topMargin + cParams.bottomMargin; } } width = Math.max(tWidth, bWidth); //上面两个 和下面两个 宽比较,用最大的 height = Math.max(lHeight, rHeight);//左边 和右边两个 宽比较,用最大的 /** * 如果是wrap_content设置为我们计算的值 * 否则:直接设置为父容器计算的值 * //设置该ViewGroup的大小 * 如果是 EXACTLY 模式(父容器能完全确定此容器的宽高),则 父容器给当前容器的大小为真正大小 * 否则(wrat_content)按照自己计算的宽高 给这个容器使用 */ setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height); } // abstract method in viewgroup @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; /** * 遍历所有childView根据其宽和高,以及margin进行布局 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); int cl = 0, ct = 0, cr = 0, cb = 0; switch (i) { case 0: cl = cParams.leftMargin; ct = cParams.topMargin; break; case 1: cl = getWidth() - cWidth - cParams.rightMargin; ct = cParams.topMargin; break; case 2: cl = cParams.leftMargin; ct = getHeight() - cHeight - cParams.bottomMargin; break; case 3: cl = getWidth() - cWidth - cParams.rightMargin; ct = getHeight() - cHeight - cParams.bottomMargin; break; } cr = cl + cWidth; cb = cHeight + ct; childView.layout(cl, ct, cr, cb); } } /** * 如果要自定义ViewGroup支持子控件的layout_margin参数,则自定义的ViewGroup类必须重载generateLayoutParams()函数, * 并且在该函数中返回一个ViewGroup.MarginLayoutParams派生类对象,这样才能使用margin参数。 */ @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { Log.e(TAG, "generateDefaultLayoutParams"); return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override protected ViewGroup.LayoutParams generateLayoutParams( ViewGroup.LayoutParams p) { Log.e(TAG, "generateLayoutParams p"); return new MarginLayoutParams(p); } /* * if (heightMode == MeasureSpec.UNSPECIFIED) { int tmpHeight = 0 ; LayoutParams lp = getLayoutParams(); if (lp.height == LayoutParams.MATCH_PARENT) { Rect outRect = new Rect(); getWindowVisibleDisplayFrame(outRect); tmpHeight = outRect.height(); }else { tmpHeight = getLayoutParams().height ; } height = Math.max(height, tmpHeight); } */ }
布局 xml
<com.example.zhy_custom_viewgroup.CustomImgContainer xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#AA333333" > <TextView android:layout_width="150dp" android:layout_height="150dp" android:background="#E5ED05" android:gravity="center" android:text="0" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> <TextView android:layout_width="50dp" android:layout_height="50dp" android:background="#00ff00" android:gravity="center" android:text="1" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> <TextView android:layout_width="50dp" android:layout_height="50dp" android:background="#ff0000" android:gravity="center" android:text="2" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> <TextView android:layout_width="150dp" android:layout_height="150dp" android:background="#0000ff" android:gravity="center" android:text="3" android:textColor="#FFFFFF" android:textSize="22sp" android:textStyle="bold" /> </com.example.zhy_custom_viewgroup.CustomImgContainer>
参考: http://blog.csdn.net/lmj623565791/article/details/38339817
相关推荐
自定义View和viewGroup
自定义Viewgroup 继承了FrameLayout 实现了下拉刷新,效果不错呦
自定义ViewGroup学习 最简单的模式,显示一个TextView到自定义ViewGroup中
最近有些空闲时间,我有回顾了一下自定义控件的一些东西,我自定义了一个ViewPager,性能不太好,所以上传到这和大家交流学习
自定义ViewGroup进一步学习,显示两个TextView到自定义控件中,对两个TextView进行布局
Android自定义组件开发详解,让你彻底理解自定义组件(自定义View、ViewGroup等,彻底了解canvas和paint的基本和高级使用方法)
自定义ViewGroup+Adapter
自定义VIewGroup组合控件,包括事件的处理,可以运行,值得学习
自定义Viewgroup,其中包括三个listview,但拖拽中间listview的上部,3个listview一起运动。
自定义下拉刷新,适用于多种控件,不止listview
自定义ViewGroup(高度不同的列表) MIT License Copyright (c) 2017 JiaoZhengXiang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated ...
自定义ViewGroup,根据手势滑动界面
主要介绍了Android自定义ViewGroup实现FlowLayout标签流容器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
自定义ViewGroup实现瀑布流,图片加载,图片回收,跟改列数,滑动加载。
6.2 自定义组件的基本结构 164 6.3 重写onMeasure方法 166 6.4 组件属性 175 6.4.1 属性的基本定义 175 6.4.2 读取来自style和theme中的属性 181 6.5 案例1:圆形ImageView组件 186 6.6 案例2:验证码组件CodeView ...
该资源包含了一个利用自定义的viewgroup实现的slidingmenu,简单易懂。
参考网友资料,加上自己苦苦研究,打造一款特有个性的维信联系人效果demo。与您分享,欢迎学习。由于开发期间受尽折磨,略需积分,见谅。原文参考:http://write.blog.csdn.net/postlist
模仿ViewPager的效果,自定义继承Linerlayout,学习的例子。
参考网友资料,加上自己苦苦研究,打造一款特有个性的维信联系人效果demo。与您分享,欢迎学习。由于开发期间受尽折磨,略需积分,见谅。原文参考:http://write.blog.csdn.net/postlist
最近写项目的时候遇到一个问题,有很多数据,每一行的按钮都不一样,我们知道在Android中自带的列表控件每一行的展示的个数都是一样的,所以后来自定义了一下ViewGroup,上传到csdn上面,希望和大家交流学习