<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>
时间: 2024-09-29 18:44:20

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

读书笔记_《50 Android Hacks》之一 linearlayout的weightsum及weights

最近在读<50 Android Hacks>,准备谢谢读书笔记,并不断丰满一下. 听到过这样的问题,“如果我想让一个button占父控件的50%,应该怎么办”. 通常来说,我们可以使用linearlayout其中的属性  android:layout_weight属性 在实现方法上来说,有几种方法来实现. android的设备有不同的size,对于不同的屏幕尺寸,我们应该有一种普遍 适用的方法. 我们可以使用layout_weight以及weightSum属性来填满layout的剩余空间. 其

android 1.6 launcher研究之自定义ViewGroup (转 2011.06.03(二)——— android 1.6 launcher研究之自定义ViewGroup )

2011.06.03(2)——— android 1.6 launcher研究之自定义ViewGroup2011.06.03(2)——— android 1.6 launcher研究之自定义ViewGroup 1.用xml来作为ViewGroup里面的View参考:http://www.eoeandroid.com/thread-30888-1-1.html MyViewGroup.java package com.lp; import android.content.Context; impo

50 Android Hacks阅读笔记

Hack 1.善用weightSum和layout_weight. 问题提出:尝试做一个button的宽度是父View的一半的效果. 关键词:weightSum = 1 , layout_weight=0.5 Hack 2.常用include和ViewStub 问题提出:如何减少复杂界面的绘制时间. 关键词:include复用,外部定义layout_width,layout_height:ViewStub占位,VISIBLE设置 Hack 3.自定义ViewGroup 问题提出:如何使用自定义V

Android View体系(十一)自定义ViewGroup

相关文章 Android View体系(一)视图坐标系 Android View体系(二)实现View滑动的六种方法 Android View体系(三)属性动画 Android View体系(四)从源码解析Scroller Android View体系(五)从源码解析View的事件分发机制 Android View体系(六)从源码解析Activity的构成 Android View体系(七)从源码解析View的measure流程 Android View体系(八)从源码解析View的layout

【自定义控件】自定义ViewGroup 在ViewGroup中显示TextView

需求:在ViewGroup中显示一个TextView 1.继承ViewGroup 必须要实现其构造方法和一个onLayout方法 构造函数的处理: public CusViewGroup(Context context) { this(context, null); } public CusViewGroup(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CusViewGroup(Context

如何在android studio中cordova的混合开发

基于Android Studio 中Cordova的开发 cordova简介 Cordova的前身是PhoneGap 官网: (http://cordova.io) Cordova应是运行在客户端本地应用容器的web应用.因此,运行在Cordova容器中的Html5应用的结构和传统的基于web服务器的有所不同.传统的web应用中服务器端做了大部分工作,比如按照用户请求传回生成的内容.而Cordova这种容器中的应用本身包括了所需要的静态页面,用户请求一般由js代码响应并与服务器交互,这样与服务器

ScrollerLayout——可横向滚动的自定义viewgroup

具体功能看效果图: 小贴士---如何录屏 使用手机自带的录屏软件,录制后为mp4格式,然后再使用下面这个网址介绍的方法,转为gif(我是用的是在线转的那个,挺好用) Android手机如何录制屏幕及转GIF 这个自定义控件涉及到的知识点: 自定义ViewGroup中onMeasure和onLayout的写法 弹性滚动Scroller的用法 速度轨迹追踪器VelocityTracker的用法 如何处理滑动事件冲突 dispatchTouchEvent:(外部拦截)告诉此ScrollLayout的父

Android XML中引用自定义内部类view的四个why

今天碰到了在XML中应用以内部类形式定义的自定义view,结果遇到了一些坑.虽然通过看了一些前辈写的文章解决了这个问题,但是我看到的几篇都没有完整说清楚why,于是决定做这个总结. 使用自定义内部类view的规则 本文主要是总结why,所以先把XML布局文件中引用内部类的自定义view的做法摆出来,有四点: 自定义的类必须是静态类: 使用view作为XML文件中的tag,注意,v是小写字母,小写字母v,小写字母v: 添加class属性,注意,没有带android:命名空间的,表明该自定义view

Android项目中使用自定义进度加载Dialog

转载: http://www.androidchina.net/2297.html 1.首先定义动画 <?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:toDegrees="3