您的位置:首页 > 其它

自适应网格布局DashboardLayout改写

2014-07-04 16:03 369 查看
原来的DashboardLayout.java的下载地址

它是一个自适应的网格布局,所谓的自适应是指当它的布局会根据子view的数量进行调整,具体效果把上述代码下载下来运行就知道了。当它的子view数量是奇数时,它的布局是1*N,垂直排列,居中显示.如果是偶数,它的布局就是n*M,居中显示。

针对子View的数量是偶数的情况,它是通过遍历的形式(初始化列数为1),判断每个子View之间的水平方向上和垂直方向上的间隔之差达到最小值来决定最终的布局(即应该用几行和几列)

int spaceDifference;

// Horizontal and vertical space between items
int hSpace = 0;
int vSpace = 0;

int cols = 1;
int rows;

while (true) {
rows = (visibleCount - 1) / cols + 1;

hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));

spaceDifference = Math.abs(vSpace - hSpace);
if (spaceDifference < bestSpaceDifference) {
// Found a better whitespace squareness/ratio
bestSpaceDifference = spaceDifference;

// If we found a better whitespace squareness and there's only 1
// row, this is
// the best we can do.
if (rows == 1) {
break;
}
} else {
// This is a worse whitespace ratio, use the previous value of
// cols and exit.
--cols;
rows = (visibleCount - 1) / cols + 1;
hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
break;
}

++cols;
}


以下是我改写的DashboardLayout,添加了动态addChildView和removeChildView的方法,还有当子view的数量是奇数时,也按照子View数量为偶数的情况去处理。

package com.example.gridviewtest;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.ImageView.ScaleType;

/**
* Custom layout that arranges children in a grid-like manner, optimizing for
* even horizontal and vertical whitespace.
*/
public class DashboardLayout extends ViewGroup {

private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
private Object mSyncLock = new Object();
private OnClickListener mOnClickListener;

public DashboardLayout(Context context) {
super(context, null);
init();
}

public DashboardLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
init();
}

public DashboardLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

private void init(){
setClickable(true);
mOnClickListener = new OnClickListener() {

@Override
public void onClick(View v) {
synchronized (mSyncLock) {
int childCount = getChildCount();
for(int i = 0;i < childCount;i++){
if(v == getChildAt(i)){
Toast.makeText(getContext(), ""+i, Toast.LENGTH_SHORT).show();
}
}
}
}
};
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxChildWidth = 0;
mMaxChildHeight = 0;

final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);

final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
// get the size of child view
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) {
int width = r - l;
int height = b - t;
t = 0;
final int count = getChildCount();

// Calculate the number of visible children.
int visibleCount = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
++visibleCount;
}

if (visibleCount == 0) {
return;
}

// Calculate what number of rows and columns will optimize for even
// horizontal and
// vertical whitespace between items. Start with a 1 x N grid, then try
// 2 x N, and so on.
int bestSpaceDifference = Integer.MAX_VALUE;
int spaceDifference;

// Horizontal and vertical space between items
int hSpace = 0;
int vSpace = 0;

int cols = 1;
int rows;

while (true) {
rows = (visibleCount - 1) / cols + 1;

hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));

spaceDifference = Math.abs(vSpace - hSpace);
if (spaceDifference < bestSpaceDifference) {
// Found a better whitespace squareness/ratio
bestSpaceDifference = spaceDifference;

// If we found a better whitespace squareness and there's only 1
// row, this is
// the best we can do.
if (rows == 1) {
break;
}
} else {
// This is a worse whitespace ratio, use the previous value of
// cols and exit.
--cols;
rows = (visibleCount - 1) / cols + 1;
hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
break;
}

++cols;
}

// Lay out children based on calculated best-fit number of rows and
// cols.

// If we chose a layout that has negative horizontal or vertical space,
// force it to zero.
// ebirdfighter think it may be cause some serious problem
hSpace = Math.max(0, hSpace);
vSpace = Math.max(0, vSpace);

// Re-use width/height variables to be child width/height.
width = (width - hSpace * (cols + 1)) / cols;
height = (height - vSpace * (rows + 1)) / rows;
int left, top;
int col, row;
int visibleIndex = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}

row = visibleIndex / cols;
col = visibleIndex % cols;

left = l + hSpace * (col + 1) + width * col;
top = t + vSpace * (row + 1) + height * row;
child.layout(left, top,(left + width), (top + height));

++visibleIndex;
}
}
/**
* add an ImageView dynamicly
*/
public void addChild() {
synchronized (mSyncLock) {
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.ic_launcher);
imageView.setScaleType(ScaleType.CENTER_INSIDE);
imageView.setOnClickListener(mOnClickListener);
addView(imageView, new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
/**
* remove an ImageView dynamicly
*/
public void removeChild() {
synchronized (mSyncLock) {
if(getChildCount() > 0){
removeViewAt(getChildCount() - 1);
}
}
}
}


上两张效果图;



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: