`

自定义容器组件ViewGroup

 
阅读更多

 

 * 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

    自定义View和ViewGroup是Android应用程序中非常重要的组件,它们都是Android UI组件树的基础。View是Android UI组件树的最基本单位,每个View都可以是一个独立的控件,例如Button、TextView、ImageView等。ViewGroup...

    继承ViewGroup自定义ViewPager

    `ViewGroup`是Android UI组件的基础,它作为容器可以包含多个`View`或`ViewGroup`,形成了我们看到的各种复杂的布局。`ViewPager`则是一种常见的滑动视图容器,常用于实现页面间的平滑切换,尤其在实现TabLayout或者...

    Android 手把手教您自定义ViewGroup(一)

    首先,自定义ViewGroup意味着你需要扩展`android.view.ViewGroup`类,这是一个容器,可以包含多个子视图(Views)。ViewGroup负责布局管理,包括子视图的位置和大小计算。在自定义过程中,我们通常会重写以下几个...

    android自定义组件demo

    自定义组件通常从`View`或`ViewGroup`派生。首先,你需要创建一个新的Java类,继承自`View`或`ViewGroup`。`View`是基本的UI元素,而`ViewGroup`用于管理多个子视图,相当于布局容器。在子类中,你需要重写`onDraw...

    自定义ViewGroup

    在Android开发中,自定义ViewGroup是一项常见的任务,它允许开发者根据特定需求创建自定义的布局组件。在这个案例中,我们看到的是一个模仿ViewPager效果的自定义ViewGroup,它继承了LinearLayout。ViewPager是一个...

    自定义ViewGroup+Adapter

    `ViewGroup`是Android UI框架中的核心组成部分,它是所有视图容器的基类,如`LinearLayout`、`RelativeLayout`等。`ViewGroup`负责管理其子视图(`View`)的布局,包括位置、大小和显示顺序。开发者自定义`ViewGroup...

    自定义ViewGroup实现垂直滚动

    首先,理解ViewGroup是Android UI体系结构的关键部分,它是一个容器,用于管理其子视图(Views)。在Android中,LinearLayout、RelativeLayout等都是内置的ViewGroup实例,它们提供了预定义的布局策略。然而,对于...

    android 自定义组件

    View是Android UI系统中最基本的元素,如按钮、文本框等,而ViewGroup则作为容器,用来管理多个View,如布局(LinearLayout、RelativeLayout等)。 创建自定义组件的步骤主要包括以下几个方面: 1. **定义组件类**...

    Android中使用自定义ViewGroup的总结

    总结来说,自定义ViewGroup在Android开发中扮演着重要角色,它允许开发者超越标准布局组件的限制,实现更加灵活和复杂的界面设计。通过理解并掌握自定义ViewGroup的基本流程和注意事项,开发者可以创建出满足特定...

    自定义ViewGroup垂直水平滑动解决ViewPager冲突

    在Android开发中,自定义ViewGroup是扩展UI组件能力的重要方式。ViewGroup作为一个容器,可以包含多个子View,并管理它们的布局和交互。本话题主要探讨如何创建一个自定义的ViewGroup,使其既能支持垂直滑动,又能...

    自定义左右滑动的ViewGroup(类似QQ会话列表项)

    `ViewGroup`是Android UI层次结构中的容器,用于管理多个子视图(`View`或`ViewGroup`)。我们可以通过继承`ViewGroup`来创建自定义布局,这样就可以自由地定义其行为和外观。 在实现滑动删除功能时,我们将使用`...

    Android自定义ViewGroup实现标签流容器FlowLayout

    它是View的子类,意味着ViewGroup既可以是单个组件,也可以是一个由多个组件组成的复合组件。 2. Android系统提供了多种预定义的ViewGroup,如LinearLayout、RelativeLayout、FrameLayout等。其中,LinearLayout按...

    android自定义viewgroup实现slidingMenu

    自定义ViewGroup是Android开发中的一个重要环节,它是对默认视图容器(如LinearLayout、RelativeLayout等)的扩展。通过自定义ViewGroup,我们可以实现更复杂的行为和动画效果。在实现SlidingMenu的过程中,我们需要...

    Android自定义组件一[文].pdf

    2. 创建ViewGroup布局子类,通过集成LinearLayout、RelativeLayout等布局容器,自定义布局行为。 3. 结合上述两种方法,利用属性资源进行更复杂的定制。 文章中给出了几个具体的自定义组件示例: 1. **Loading 动态...

    android自定义组件(二)

    首先,自定义组件的基础是理解Android的View和ViewGroup系统。View是UI的基本元素,如按钮、文本框等,而ViewGroup是容器,用于组织和管理多个View。自定义组件通常是在这两个类的基础上进行扩展。 1. **创建自定义...

    android自定义组件(三)

    首先,自定义组件的基础是理解Android的View和ViewGroup系统。View是UI的基本元素,如按钮、文本框等,而ViewGroup是容器,用于组织和管理多个View。自定义组件通常是在这两个类的基础上进行扩展。 1. **创建自定义...

    自定义viewgroup

    文件可能包含了实现特定布局逻辑的自定义ViewGroup类,以及对应的XML布局文件,用于在界面上展示这个自定义组件。通过阅读和分析这些代码,开发者能更好地理解自定义ViewGroup的工作原理,并学会如何在自己的项目中...

Global site tag (gtag.js) - Google Analytics