android自定义viewgroup实现等分格子布局
2014-06-15 10:41
666 查看
http://www.cnblogs.com/Jaylong/p/viewgroup.html
先上效果图:
实现这样的效果:
一般的思路就是,直接写布局文件,用LinearLayout 嵌套多层子LinearLayout,然后根据权重layout_weight可以达到上面的效果
还有就是利用gridview了,但是这里的需求就是不能上下滑动,使用gridview的时候还要计算布局的高度,否则内容超出下滑;
开始我是用的第一种,直接在布局文件实现了,但是后来发现代码太多太恶心哦,所以我继承viewGroup,重写两个关键的方法:onLayout(),onMeasure()
我的大致思路:
1.计算当前视图宽度和高度,然后根据边距,算出每个布局的item需要分配的多少宽度和高度:
2.支持adapter的方式,动态添加每一项,还可以设置每一项点击事件
好了,直接上关键代码:
要实现adapter也很简单,自定义一个接口,下面给出完整的代码
这里我给出完整的demo下载:click me!!!
先上效果图:
实现这样的效果:
一般的思路就是,直接写布局文件,用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);
}
});
}
}
}
这里我给出完整的demo下载:click me!!!
相关文章推荐
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android自定义ViewGroup自动换行实现滑动任意布局及事件处理效果
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现(支持按钮间隔)
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android自定义ViewGroup实现流式布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现