首页 > 代码库 > <50 android hacks>中的卡牌问题---自定义ViewGroup

<50 android hacks>中的卡牌问题---自定义ViewGroup

学安卓的时间并不算短,但是一直都没有认认真真的看过,前段时间看见<50 android hacks>,觉得这本书写的真的不错,国内也有中文版.

要求显示上面的效果,通常我就会用RelativeLayout和layout_margin*来实现

In this hack, we’ll look at another way of creating
the same type of layout—we’ll create a custom View-
Group . The benefits of using a custom ViewGroup
instead of adding margins by hand in an XML file are
these:

A.It’s easier to maintain if you’re using it in different activities.

B. You can use custom attributes to customize the position of the ViewGroup children.
C. The XML will be easier to understand because it’ll be more concise.
D. If you need to change the margins, you won’t need to recalculate by hand every child’s margin.



下面用ViewGroup实现:

java:

package com.example.lock;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
/**
 * 
 * @author kutear
 *
 */


public class ExampleView extends ViewGroup{
    private int horizontal_spacing = 0; 
    private int vertical_spacing = 0; 
	TypedArray t = null;
	public ExampleView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	//这里是取得< ExampleView />的自定义属性
	 t = context.obtainStyledAttributes(attrs, com.example.lock.R.styleable.ExampleView);
	 horizontal_spacing = t.getDimensionPixelSize(com.example.lock.R.styleable.ExampleView_horizontal_spacing, 20);
	 vertical_spacing = t.getDimensionPixelSize(com.example.lock.R.styleable.ExampleView_vertical_spacing, 30);
	 int marginleft = t.getDimensionPixelSize(com.example.lock.R.styleable.ExampleView_layout_marginleft,10);
	 Log.v("XML-height",""+ horizontal_spacing);
	 Log.v("XML-width",""+ vertical_spacing);
	 Log.v("XML-MarginLeft",""+ marginleft);
	 t.recycle();
	}
   
	/**
	 * 用来计算Parent和Child的尺寸
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		
		int width = MeasureSpec.getSize(widthMeasureSpec); //if fill_parent,ViewGroup的宽为该值..
		int height = MeasureSpec.getSize(heightMeasureSpec);//同上
		
		Log.v("width", "width:"+width);
		Log.v("height", "height:"+height);
		int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
		int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
		Log.v("Mode--H:", ""+modeHeight);
		Log.v("Mode--W:", ""+modeWidth);
		Log.v("AT_MOST:",""+MeasureSpec.AT_MOST);
		Log.v("EXACTLY:",""+MeasureSpec.EXACTLY);
		Log.v("UNSPECIFIED:",""+MeasureSpec.UNSPECIFIED);
		int childHeight = 0; //Child的总高度....用来确定ViewGroup是wrap_content时的高度
		int childWidth = 0;  //同上
		int count = getChildCount();
		
		for(int i=0;i<count;i++){
			View child = getChildAt(i);
			//This will display 0
			Log.v("before-Child-size",""+ child.getMeasuredHeight());
			//计算Child的大小
			measureChild(child,widthMeasureSpec,heightMeasureSpec);
			//This will display ready size
			Log.v("after-Child-Size",""+ child.getMeasuredHeight());
			ExampleView.LayoutParams lp = (ExampleView.LayoutParams) child.getLayoutParams();
			int cHeight = child.getMeasuredHeight();
			int cWidth = child.getMeasuredWidth();
			if (i==0) {
				childHeight += cHeight;
				childWidth += cWidth+lp.marginleft;
			}else {
				childHeight += vertical_spacing;
				childWidth +=horizontal_spacing+lp.marginleft;
			}
		}
		Log.v("Wrap_content:", childWidth+"---"+childHeight);
		
		setMeasuredDimension(MeasureSpec.AT_MOST==modeWidth?childWidth:width,//warp_content时为前者
				MeasureSpec.AT_MOST==modeHeight?childHeight:height); //parent's Size, fill_parent or wrap_content
	}
	
	
	/**
	 * 绘制Child的位置
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		/**
		 * 参数表示:l-->left  ViewGroup的左边的坐标
		 *         其他的类似
		 *   ViewGroup在整个屏幕中的位置....
		 *   不是ViewGroup的相对位置...
		 *   
		 *   
		 */
		
		// TODO Auto-generated method stub
		 int WT_S=0; //下一View的开始位置 
		 //int WT_E=0; //下一VIew的结束位置
		 int childCount = getChildCount();   
		 Log.v("-----", "L="+l+"--T="+t+"--R="+r+"--B="+b);
		    for (int i = 0; i < childCount; i++) {   
		        View childView = getChildAt(i);   
		        // 获取在onMeasure中计算的视图尺寸   
		        int measureHeight = childView.getMeasuredHeight();   
		        int measuredWidth = childView.getMeasuredWidth();   
		        Log.v("Child-Height", measureHeight+"");
		        Log.v("Child-Width", measuredWidth+"");
		        ExampleView.LayoutParams lp = (ExampleView.LayoutParams) childView.getLayoutParams();
		        Log.v("leftMargin",""+lp.marginleft);
		        Log.v("leftMargin",""+lp.rightMargin);
		        WT_S += (i==0?0:horizontal_spacing)+lp.marginleft;
		        Log.v("WT_S", WT_S+"");
		        //这里的四个方向的参数位相对与ViewGroup的位置,,ViewGroup的左上角位(0,0)
		        childView.layout(WT_S, vertical_spacing*i,
		        		WT_S+measuredWidth, vertical_spacing*i+measureHeight);
		        
		        
		    }   
	}
	
	@Override
    protected android.view.ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
    }
 
    @Override
    public android.view.ViewGroup.LayoutParams generateLayoutParams(
            AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }
 
    @Override
    protected android.view.ViewGroup.LayoutParams generateLayoutParams(
            android.view.ViewGroup.LayoutParams p) {
        return new LayoutParams(p);
    }
	
	
    public static class LayoutParams extends MarginLayoutParams {
        private int horizontal_spacing = 0; 
        private int vertical_spacing = 0; 
        public int marginleft = -1;
        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
 
            TypedArray ta = c.obtainStyledAttributes(attrs,
                    R.styleable.ExampleView);
           //此处是取得ViewGroup中的Child中的自定义属性
            horizontal_spacing = ta.getInt(R.styleable.ExampleView_horizontal_spacing, -1);
            vertical_spacing = ta.getInt(R.styleable.ExampleView_vertical_spacing, -1);
            marginleft = ta.getDimensionPixelSize(R.styleable.ExampleView_layout_marginleft, 0);
            int paddingleft = ta.getIndex(R.styleable.View_paddingEnd);
            Log.v("Padding",""+paddingleft); 
            Log.v("marginleft",""+marginleft); 
            ta.recycle();
        }
 
        public LayoutParams(int width, int height) {
            super(width, height);
        }
 
 
        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
            super(source);
        }
 
        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }
    }

}

xml:

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ExampleView">
        <attr name="horizontal_spacing" format="dimension" />
        <attr name="vertical_spacing" format="dimension" />
        <attr name="layout_marginleft" format="dimension"/>
    </declare-styleable>

</resources>

test.aml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cascade="http://schemas.android.com/apk/res/com.example.lock"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="MMMMMM" >
    </TextView>


    <com.example.lock.ExampleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        cascade:layout_marginleft="20dp"
        android:background="#abcdef"
        cascade:horizontal_spacing="30dp"
        cascade:vertical_spacing="30dp" >

        <TextView
            android:layout_width="100dp"
            android:layout_height="150dp"
            android:background="#FF0000"
            android:text="AAA" />

        <TextView
            android:layout_width="100dp"
            android:layout_height="150dp"
            cascade:layout_marginleft="20dp"
            android:background="#0000FF"
            android:text="BBB" />

        <TextView
            android:layout_width="100dp"
            android:layout_height="150dp"
            android:background="#00FF00"
            android:text="CCC" />
    </com.example.lock.ExampleView>

</LinearLayout>


<50 android hacks>中的卡牌问题---自定义ViewGroup