自定义控件(15)---ViewGroup绘制的自定义子View的margin注意

自定义控件(15)---ViewGroup绘制的自定义子View的margin注意_第1张图片

activity_main.xml

<com.aigestudio.customviewdemo.views.CustomLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF597210"
    android:orientation="vertical" >

    <com.aigestudio.customviewdemo.views.IconView
        android:id="@+id/main_pv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="20dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="20dp"
        android:text="AigeStudio" />


</com.aigestudio.customviewdemo.views.CustomLayout>

MainActivity

package com.aigestudio.customviewdemo.activities;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;

import com.aigestudio.customviewdemo.R;
import com.aigestudio.customviewdemo.views.ImgView;

public class MainActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
}

IconView

package com.aigestudio.customviewdemo.views;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

import com.aigestudio.customviewdemo.R;

public class IconView extends View {
	private Bitmap mBitmap;// 位图

	private enum Ratio {
		WIDTH, HEIGHT
	}

	public IconView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 初始化
		init();
	}

	/**
	 * 初始化
	 */
	private void init() {
		/*
		 * 获取Bitmap
		 */
		if (null == mBitmap) {
			mBitmap = BitmapFactory.decodeResource(getResources(),
					R.drawable.logo);
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 声明一个临时变量来存储计算出的测量值
		int resultWidth = 0;

		// 获取宽度测量规格中的mode
		int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

		// 获取宽度测量规格中的size
		int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
		/*
		 * 如果爹心里有数
		 */
		if (modeWidth == MeasureSpec.EXACTLY) {
			// 那么儿子也不要让爹难做就取爹给的大小吧
			resultWidth = mBitmap.getWidth() + getPaddingLeft()
					+ getPaddingRight();
		}
		/*
		 * 如果爹心里没数
		 */
		else {
			// 那么儿子可要自己看看自己需要多大了
			resultWidth = mBitmap.getWidth() + getPaddingLeft()
					+ getPaddingRight();

			/*
			 * 如果爹给儿子的是一个限制值
			 */
			if (modeWidth == MeasureSpec.AT_MOST) {
				// 那么儿子自己的需求就要跟爹的限制比比看谁小要谁
				resultWidth = Math.min(resultWidth, sizeWidth);
			}
		}

		int resultHeight = 0;
		int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
		int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

		if (modeHeight == MeasureSpec.EXACTLY) {
			resultHeight = sizeHeight;
		} else {
			resultHeight = mBitmap.getHeight() + getPaddingTop()
					+ getPaddingBottom();
			if (modeHeight == MeasureSpec.AT_MOST) {
				resultHeight = mBitmap.getHeight() + getPaddingTop()
						+ getPaddingBottom();
			}
		}

		// 设置测量尺寸
		setMeasuredDimension(resultWidth, resultHeight);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		canvas.drawBitmap(mBitmap, getPaddingLeft(), getPaddingTop(), null);
	}
}

CustomLayout

package com.aigestudio.customviewdemo.views;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

public class CustomLayout extends ViewGroup {

	public CustomLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 声明临时变量存储父容器的期望值
		int parentDesireWidth = 0;
		int parentDesireHeight = 0;

		/*
		 * 如果有子元素
		 */
		if (getChildCount() > 0) {
			// 那么遍历子元素并对其进行测量
			for (int i = 0; i < getChildCount(); i++) {

				// 获取子元素
				View child = getChildAt(i);

				// 获取子元素的布局参数
				CustomLayoutParams clp = (CustomLayoutParams) child
						.getLayoutParams();

				// 测量子元素并考虑外边距
				measureChildWithMargins(child, widthMeasureSpec, 0,
						heightMeasureSpec, 0);

				// 计算父容器的期望值
				parentDesireWidth += child.getMeasuredWidth() + clp.leftMargin
						+ clp.rightMargin;
				parentDesireHeight += child.getMeasuredHeight() + clp.topMargin
						+ clp.bottomMargin;
			}

			// 考虑父容器的内边距
			parentDesireWidth += getPaddingLeft() + getPaddingRight();
			parentDesireHeight += getPaddingTop() + getPaddingBottom();

			// 尝试比较建议最小值和期望值的大小并取大值
			parentDesireWidth = Math.max(parentDesireWidth,
					getSuggestedMinimumWidth());
			parentDesireHeight = Math.max(parentDesireHeight,
					getSuggestedMinimumHeight());
		}

		/**
		 * 这个方法的主要作用就是根据你提供的大小和模式,返回你想要的大小值,这个里面根据传入模式的不同来做相应的处理。
		 */
		setMeasuredDimension(resolveSize(parentDesireWidth, widthMeasureSpec),
				resolveSize(parentDesireHeight, heightMeasureSpec));
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// 获取父容器内边距
		int parentPaddingLeft = getPaddingLeft();
		int parentPaddingTop = getPaddingTop();

		/*
		 * 如果有子元素
		 */
		if (getChildCount() > 0) {
			// 声明一个临时变量存储高度倍增值
			int mutilHeight = 0;

			// 那么遍历子元素并对其进行定位布局
			for (int i = 0; i < getChildCount(); i++) {
				// 获取一个子元素
				View child = getChildAt(i);

				CustomLayoutParams clp = (CustomLayoutParams) child
						.getLayoutParams();

				// 通知子元素进行布局
				// 此时考虑父容器内边距和子元素外边距的影响
				child.layout(parentPaddingLeft + clp.leftMargin, mutilHeight+ parentPaddingTop + clp.topMargin,
						child.getMeasuredWidth() + parentPaddingLeft+ clp.leftMargin,
						child.getMeasuredHeight()+ mutilHeight + parentPaddingTop+ clp.topMargin);

				// 改变高度倍增值
				mutilHeight += child.getMeasuredHeight() + clp.topMargin
						+ clp.bottomMargin;
			}
		}
	}

	/**
	 * 生成默认的布局参数
	 */
	@Override
	protected CustomLayoutParams generateDefaultLayoutParams() {
		return new CustomLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
				ViewGroup.LayoutParams.MATCH_PARENT);
	}

	/**
	 * 生成布局参数 将布局参数包装成我们的
	 */
	@Override
	protected android.view.ViewGroup.LayoutParams generateLayoutParams(
			android.view.ViewGroup.LayoutParams p) {
		return new CustomLayoutParams(p);
	}

	/**
	 * 生成布局参数 从属性配置中生成我们的布局参数
	 */
	@Override
	public android.view.ViewGroup.LayoutParams generateLayoutParams(
			AttributeSet attrs) {
		return new CustomLayoutParams(getContext(), attrs);
	}

	/**
	 * 检查当前布局参数是否是我们定义的类型这在code声明布局参数时常常用到
	 */
	@Override
	protected boolean checkLayoutParams(android.view.ViewGroup.LayoutParams p) {
		return p instanceof CustomLayoutParams;
	}

	/**
	 * 
	 * @author AigeStudio {@link http://blog.csdn.net/aigestudio}
	 * 
	 */
	public static class CustomLayoutParams extends MarginLayoutParams {

		public CustomLayoutParams(MarginLayoutParams source) {
			super(source);
		}

		public CustomLayoutParams(android.view.ViewGroup.LayoutParams source) {
			super(source);
		}

		public CustomLayoutParams(Context c, AttributeSet attrs) {
			super(c, attrs);
		}

		public CustomLayoutParams(int width, int height) {
			super(width, height);
		}
	}
}


你可能感兴趣的:(自定义控件(15)---ViewGroup绘制的自定义子View的margin注意)