A5下载 - 努力做内容最丰富最安全的下载站!

A5站长下载站

当前位置:A5下载 > 编程开发 > 安卓开发 > 自定义ViewGroup的实现

自定义ViewGroup的实现

时间:2015-07-08 14:31作者:zhao人气:187

在平常的应用开发中,我们不时的需要进行自定义的ViewGroup的开发以适应我们的需求。下面是一个简单的demo用于说明自定义ViewGroup。

1. 在自定义ViewGroup的过程中我们首先需要学会自定义属性,自定义属性需要在value/attrs.xml,使用<declare-styleable>标签进行声明:

<declare-styleable name="CascadeLayout">

<attr name="horizontal_spacing" format="dimension"/>

<attr name="vertical_spacing" format="dimension"/>

</declare-styleable>

2. 在定义的ViewGroup中,我们需要在构造函数中去读取这些自定义的属性,用于实现我们需要的业务处理。读取自定义属性需要使用TypedArray类。

public CascadeLayout(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs,

R.styleable.CascadeLayout);

try {

mHorizontalSpacing = ta.getDimensionPixelSize(

R.styleable.CascadeLayout_horizontal_spacing,

this.getResources().getDimensionPixelSize(

R.dimen.cascade_horizontal_spacing));

mVerticalSpacing = ta.getDimensionPixelSize(

R.styleable.CascadeLayout_vertical_spacing,

this.getResources().getDimensionPixelSize(

R.dimen.cascade_vertical_spaccing));

} finally {

ta.recycle();

}

}

3.在自定义ViewGroup的类中,需要实现两个函数分别是onMeasure()和onLayout(),这两个函数分别代表了测量阶段和布局阶段,不熟悉的同学可以参考这边博文http://my.oschina.net/u/565871/blog/132350。

在onMeasure()函数我们需要每个view去测量自己的大小,并且给整个ViewGroup设置大小

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int count = this.getChildCount();

int countWidth = 0;

int countHeight = this.getPaddingTop();

for (int i = 0; i < count; i++) {

View currentView = this.getChildAt(i);

//使每个view去测量自己的大小

this.measureChild(currentView, widthMeasureSpec, heightMeasureSpec);

LayoutParams lp = (LayoutParams) currentView.getLayoutParams();

countWidth = this.getPaddingLeft() + mHorizontalSpacing * i;

lp.x = countWidth;

lp.y = countHeight+lp.childVerticalSpcing;

countWidth += currentView.getMeasuredWidth();

countHeight += mVerticalSpacing+lp.childVerticalSpcing;

}

//算出整个屏幕的宽度和高度

countWidth += this.getPaddingRight();

countHeight += this.getChildAt(count - 1).getMeasuredHeight()

+ this.getPaddingBottom();

//设置ViewGroup的大小

this.setMeasuredDimension(resolveSize(countWidth, widthMeasureSpec),

resolveSize(countHeight, heightMeasureSpec));

}

在onMeasure()方法中我们用到了一个LayoutParams,这个类有两个成员变量x,y,这个类是我们自定义的类用于布局的需要。

public static class LayoutParams extends ViewGroup.LayoutParams {

int x;

int y;

int childVerticalSpcing;

public LayoutParams(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs,

R.styleable.CascadeLayout_LayoutParams);

try {

childVerticalSpcing = ta

.getDimensionPixelSize(

R.styleable.CascadeLayout_LayoutParams_layout_vertical_spacing,

context.getResources()

.getDimensionPixelSize(

R.dimen.cascade_layout_vertical_spacing));

} finally {

ta.recycle();

}

}

public LayoutParams(int w, int h) {

super(w, h);

}

}

剩下的就是布局阶段,在onLayout()方法中实现,使每个view放在我们需要它在的地方。

protected void onLayout(boolean changed, int left, int top, int right,

int bottom) {

final int count = this.getChildCount();

for (int i = 0; i < count; i++) {

View currentView = this.getChildAt(i);

LayoutParams lp = (LayoutParams) currentView.getLayoutParams();

currentView.layout(lp.x, lp.y,

lp.x + currentView.getMeasuredWidth(),

lp.y + currentView.getMeasuredHeight());

}

}

这样就差不多完成了,全部的自定义的CascadeLayout.java的代码如下:

package com.cascadelayout.view;

import com.cascadelayout.main.R;

import android.content.Context;

import android.content.res.TypedArray;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

public class CascadeLayout extends ViewGroup {

int mHorizontalSpacing;

int mVerticalSpacing;

public CascadeLayout(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs,

R.styleable.CascadeLayout);

try {

mHorizontalSpacing = ta.getDimensionPixelSize(

R.styleable.CascadeLayout_horizontal_spacing,

this.getResources().getDimensionPixelSize(

R.dimen.cascade_horizontal_spacing));

mVerticalSpacing = ta.getDimensionPixelSize(

R.styleable.CascadeLayout_vertical_spacing,

this.getResources().getDimensionPixelSize(

R.dimen.cascade_vertical_spaccing));

} finally {

ta.recycle();

}

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int count = this.getChildCount();

int countWidth = 0;

int countHeight = this.getPaddingTop();

for (int i = 0; i < count; i++) {

View currentView = this.getChildAt(i);

//使每个view去测量自己的大小

this.measureChild(currentView, widthMeasureSpec, heightMeasureSpec);

LayoutParams lp = (LayoutParams) currentView.getLayoutParams();

countWidth = this.getPaddingLeft() + mHorizontalSpacing * i;

lp.x = countWidth;

lp.y = countHeight+lp.childVerticalSpcing;

countWidth += currentView.getMeasuredWidth();

countHeight += mVerticalSpacing+lp.childVerticalSpcing;

}

//算出整个屏幕的宽度和高度

countWidth += this.getPaddingRight();

countHeight += this.getChildAt(count - 1).getMeasuredHeight()

+ this.getPaddingBottom();

//设置ViewGroup的大小

this.setMeasuredDimension(resolveSize(countWidth, widthMeasureSpec),

resolveSize(countHeight, heightMeasureSpec));

}

@Override

protected void onLayout(boolean changed, int left, int top, int right,

int bottom) {

final int count = this.getChildCount();

for (int i = 0; i < count; i++) {

View currentView = this.getChildAt(i);

LayoutParams lp = (LayoutParams) currentView.getLayoutParams();

currentView.layout(lp.x, lp.y,

lp.x + currentView.getMeasuredWidth(),

lp.y + currentView.getMeasuredHeight());

}

}

public static class LayoutParams extends ViewGroup.LayoutParams {

int x;

int y;

int childVerticalSpcing;

public LayoutParams(Context context, AttributeSet attrs) {

super(context, attrs);

TypedArray ta = context.obtainStyledAttributes(attrs,

R.styleable.CascadeLayout_LayoutParams);

try {

childVerticalSpcing = ta

.getDimensionPixelSize(

R.styleable.CascadeLayout_LayoutParams_layout_vertical_spacing,

context.getResources()

.getDimensionPixelSize(

R.dimen.cascade_layout_vertical_spacing));

} finally {

ta.recycle();

}

}

public LayoutParams(int w, int h) {

super(w, h);

}

}

@Override

protected android.view.ViewGroup.LayoutParams generateDefaultLayoutParams() {

return new LayoutParams(LayoutParams.WRAP_CONTENT,

LayoutParams.WRAP_CONTENT);

}

@Override

protected android.view.ViewGroup.LayoutParams generateLayoutParams(

android.view.ViewGroup.LayoutParams p) {

return new LayoutParams(LayoutParams.WRAP_CONTENT,

LayoutParams.WRAP_CONTENT);

}

@Override

public android.view.ViewGroup.LayoutParams generateLayoutParams(

AttributeSet attrs) {

return new LayoutParams(this.getContext(), attrs);

}

}

在自定义的value/attrs.xml中的定义如下:

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

<resources>

<declare-styleable name="CascadeLayout">

<attr name="horizontal_spacing" format="dimension"/>

<attr name="vertical_spacing" format="dimension"/>

</declare-styleable>

<declare-styleable name="CascadeLayout_LayoutParams">

<attr name="layout_vertical_spacing" format="dimension"/>

</declare-styleable>

</resources>

布局文件如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

xmlns:cascade="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity" >

<com.cascadelayout.view.CascadeLayout

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@android:color/holo_orange_light"

cascade:horizontal_spacing="40dp"

cascade:vertical_spacing="40dp">

<TextView

android:layout_width="90dp"

android:layout_height="200dp"

android:text="aaa"

android:gravity="center"

android:background="#00FF00"/>

<TextView

android:layout_width="90dp"

android:layout_height="200dp"

android:text="bbb"

android:gravity="center"

android:background="#48D1CC" />

<TextView

android:layout_width="90dp"

android:layout_height="200dp"

android:text="ccc"

android:gravity="center"

cascade:layout_vertical_spacing="60dip"

android:background="#CDBE70" />

</com.cascadelayout.view.CascadeLayout>

</RelativeLayout>

最后实现的效果如下:

 

标签自定义,ViewGroup,实现,平常,应用开发,我们,不时

相关下载

查看所有评论+

网友评论

网友
您的评论需要经过审核才能显示

公众号