首页 > 代码库 > android自定义viewgroup实现等分格子布局

android自定义viewgroup实现等分格子布局

先上效果图:

实现这样的效果:

一般的思路就是,直接写布局文件,用LinearLayout 嵌套多层子LinearLayout,然后根据权重layout_weight可以达到上面的效果

还有就是利用gridview了,但是这里的需求就是不能上下滑动,使用gridview的时候还要计算布局的高度,否则内容超出下滑;

开始我是用的第一种,直接在布局文件实现了,但是后来发现代码太多太恶心哦,所以我继承viewGroup,重写两个关键的方法:onLayout(),onMeasure()

我的大致思路:

1.计算当前视图宽度和高度,然后根据边距,算出每个布局的item需要分配的多少宽度和高度:

2.支持adapter的方式,动态添加每一项,还可以设置每一项点击事件

好了,直接上关键代码:

@Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // TODO Auto-generated method stub        mMaxChildWidth = 0;        mMaxChildHeight = 0;        int modeW = 0, modeH = 0;        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED)            modeW = MeasureSpec.UNSPECIFIED;        if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.UNSPECIFIED)            modeH = MeasureSpec.UNSPECIFIED;        final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(                MeasureSpec.getSize(widthMeasureSpec), modeW);        final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(                MeasureSpec.getSize(heightMeasureSpec), modeH);        count = getChildCount();        if (count == 0) {            super.onMeasure(childWidthMeasureSpec, childHeightMeasureSpec);            return;        }        for (int i = 0; i < count; i++) {            final View child = getChildAt(i);            if (child.getVisibility() == GONE) {                continue;            }            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);            mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());            mMaxChildHeight = Math.max(mMaxChildHeight,                    child.getMeasuredHeight());        }        setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec),                resolveSize(mMaxChildHeight, heightMeasureSpec));    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // TODO Auto-generated method stub        int height = b - t;// 布局区域高度        int width = r - l;// 布局区域宽度        int rows = count % colums == 0 ? count / colums : count / colums + 1;// 行数        if (count == 0)            return;        int gridW = (width - margin * (colums - 1)) / colums;// 格子宽度        int gridH = (height - margin * rows) / rows;// 格子高度        int left = 0;        int top = margin;        for (int i = 0; i < rows; i++) {// 遍历行            for (int j = 0; j < colums; j++) {// 遍历每一行的元素                View child = this.getChildAt(i * colums + j);                if (child == null)                    return;                left = j * gridW + j * margin;                // 如果当前布局宽度和测量宽度不一样,就直接用当前布局的宽度重新测量                if (gridW != child.getMeasuredWidth()                        || gridH != child.getMeasuredHeight()) {                    child.measure(makeMeasureSpec(gridW, EXACTLY),                            makeMeasureSpec(gridH, EXACTLY));                }                child.layout(left, top, left + gridW, top + gridH);                // System.out                // .println("--top--" + top + ",bottom=" + (top + gridH));            }            top += gridH + margin;        }    }

要实现adapter也很简单,自定义一个接口,下面给出完整的代码

package com.allen.view;import static android.view.View.MeasureSpec.EXACTLY;import static android.view.View.MeasureSpec.makeMeasureSpec;import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import com.allen.mygridlayout.R;/** * @author allen * @email jaylong1302@163.com * @date 2013-11-26 下午1:19:35 * @company 富媒科技 * @version 1.0 * @description 格子布局(类似4.0中的gridlayout) */public class MyGridLayout extends ViewGroup {    private final String TAG = "MyGridLayout";    int margin = 2;// 每个格子的水平和垂直间隔    int colums = 2;    private int mMaxChildWidth = 0;    private int mMaxChildHeight = 0;    int count = 0;    GridAdatper adapter;    public MyGridLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        if (attrs != null) {            TypedArray a = getContext().obtainStyledAttributes(attrs,                    R.styleable.MyGridLayout);            colums = a.getInteger(R.styleable.MyGridLayout_numColumns, 2);            margin = (int) a.getInteger(R.styleable.MyGridLayout_itemMargin, 2);        }    }    public MyGridLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public MyGridLayout(Context context) {        this(context, null);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        // TODO Auto-generated method stub        mMaxChildWidth = 0;        mMaxChildHeight = 0;        int modeW = 0, modeH = 0;        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED)            modeW = MeasureSpec.UNSPECIFIED;        if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.UNSPECIFIED)            modeH = MeasureSpec.UNSPECIFIED;        final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(                MeasureSpec.getSize(widthMeasureSpec), modeW);        final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(                MeasureSpec.getSize(heightMeasureSpec), modeH);        count = getChildCount();        if (count == 0) {            super.onMeasure(childWidthMeasureSpec, childHeightMeasureSpec);            return;        }        for (int i = 0; i < count; i++) {            final View child = getChildAt(i);            if (child.getVisibility() == GONE) {                continue;            }            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);            mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());            mMaxChildHeight = Math.max(mMaxChildHeight,                    child.getMeasuredHeight());        }        setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec),                resolveSize(mMaxChildHeight, heightMeasureSpec));    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // TODO Auto-generated method stub        int height = b - t;// 布局区域高度        int width = r - l;// 布局区域宽度        int rows = count % colums == 0 ? count / colums : count / colums + 1;// 行数        if (count == 0)            return;        int gridW = (width - margin * (colums - 1)) / colums;// 格子宽度        int gridH = (height - margin * rows) / rows;// 格子高度        int left = 0;        int top = margin;        for (int i = 0; i < rows; i++) {// 遍历行            for (int j = 0; j < colums; j++) {// 遍历每一行的元素                View child = this.getChildAt(i * colums + j);                if (child == null)                    return;                left = j * gridW + j * margin;                // 如果当前布局宽度和测量宽度不一样,就直接用当前布局的宽度重新测量                if (gridW != child.getMeasuredWidth()                        || gridH != child.getMeasuredHeight()) {                    child.measure(makeMeasureSpec(gridW, EXACTLY),                            makeMeasureSpec(gridH, EXACTLY));                }                child.layout(left, top, left + gridW, top + gridH);                // System.out                // .println("--top--" + top + ",bottom=" + (top + gridH));            }            top += gridH + margin;        }    }    public interface GridAdatper {        View getView(int index);        int getCount();    }    /** 设置适配器 */    public void setGridAdapter(GridAdatper adapter) {        this.adapter = adapter;        // 动态添加视图        int size = adapter.getCount();        for (int i = 0; i < size; i++) {            addView(adapter.getView(i));        }    }    public interface OnItemClickListener {        void onItemClick(View v, int index);    }    public void setOnItemClickListener(final OnItemClickListener click) {        if (this.adapter == null)            return;        for (int i = 0; i < adapter.getCount(); i++) {            final int index = i;            View view = getChildAt(i);            view.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    // TODO Auto-generated method stub                    click.onItemClick(v, index);                }            });        }    }}