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>
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); } }
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); } }
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); } } }