[转载]【Android-view】listView 每个item里动态添加不定量的控件,Android 自动换行 – helloworld.MR-zz – 博客园.
问题描述:
开发过程中,遇到了在listview里面的每个item都有可能显示图片,并且需要显示的图片的数量不确定,需要自动换行。
如图:第一行显示三张图片,第二行显示四张图片。数量0—正无穷(内存支持的情况下)

解决办法:
最初就是直接从网上找Android自动换行的控件,再此感谢eoe论坛里**dahege **分享的源码。
dahege eoe论坛原文地址:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=195276
但是我直接拿来用的时候出现了个问题,就是当有四张图片的时候只显示三行。
具体解决办法如下:
a.修改values下attrs.xml文件
增加一个每行显示多少列的属性,类似gridview
<resources>
<declare-styleable name="FlowLayout">
<attr name="horizontalSpacing" format="dimension" />
<attr name="verticalSpacing" format="dimension" />
<attr name="numColumns" format="integer" /><!--这个属性为新加的-->
</declare-styleable>
<declare-styleable name="FlowLayout_LayoutParams">
<attr name="layout_breakLine" format="boolean" />
<attr name="layout_horizontalSpacing" format="dimension" />
</declare-styleable>
</resources>
b.修改FlowLayout.java 源文件
1.在构造方法里得到用户在cml文件里设置的numColumns
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
try {
mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 0);
mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 0);
numColumns = a.getInt(R.styleable.FlowLayout_numColumns, 3);//得到用户在布局文件中设置的没行显示的列数
} finally {
a.recycle();
}
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(0xffff0000);
mPaint.setStrokeWidth(2.0f);
}
2.修改onMeasure方法,由于对这块还不太了解,所以只是简单的改了一下,测试之后效果是实现了,暂未发现其他问题。应该还有更好的解决方案,希望有人指正。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight();
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
boolean growHeight = widthMode != MeasureSpec.UNSPECIFIED;
int width = 0;
int height = getPaddingTop();
int currentWidth = getPaddingLeft();
int currentHeight = 0;
boolean breakLine = false;
boolean newLine = false;
int spacing = 0;
final int count = getChildCount();
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
spacing = mHorizontalSpacing;
if (lp.horizontalSpacing >= 0) {
spacing = lp.horizontalSpacing;
}
if (growHeight && (i == numColumns||breakLine || currentWidth + child.getMeasuredWidth() > widthSize)) {
// newLine = true;
height += currentHeight + mVerticalSpacing;
width = Math.max(width, currentWidth - spacing);
currentHeight = 0;
currentWidth = getPaddingLeft();
}
// else {
// newLine = false;
// }
if (i>numColumns&&i%numColumns==0) {//主要修改的是这个判断语句,原版的判断语句是29,38,39,40行的被隐掉的。我自己用原版的判断语句有问题,
newLine = false;
}
lp.x = currentWidth;
lp.y = height;
currentWidth += child.getMeasuredWidth() + spacing;
currentHeight = Math.max(currentHeight, child.getMeasuredHeight());
breakLine = lp.breakLine;
}
if (!newLine) {
height += currentHeight;
width = Math.max(width, currentWidth - spacing);
}
width += getPaddingRight();
height += getPaddingBottom();
setMeasuredDimension(resolveSize(width, widthMeasureSpec),
resolveSize(height, heightMeasureSpec));
}
至此,就修改完毕了。
具体使用办法如下。
a.在listview的item布局文件中使用framelayout自定义控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:f="http://schemas.android.com/apk/res/你的androidmanifest.xml文件中的package属性值"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<com.xingyunhudong.view.FlowLayout
android:id="@+id/flowlaytou"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
f:numColumns="3"<!--也可以不指定,如果不指定,在FrameLayout的构造函数里,默认取值为3列-->
>
</com.xingyunhudong.view.FlowLayout>
</LinearLayout>
b.在adapter中设值
public class XXXAdapterextends BaseAdapter {
private LayoutInflater inflater;
private List<XXX> xxxList;
private Context context;
private ViewGroup.LayoutParams paramsImg, paramsVideo;
private int sw;
public HuaTiAdapter(Context context, List<xxx> xxxList) {
this.xxxList = xxxList;
this.context = context;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
sw = CommonUtils.getScreenWidth((Activity) context);
int w = context.getResources().getDimensionPixelSize(
R.dimen.xxx_img_total_width);
sw = sw - w;
paramsImg = new ViewGroup.LayoutParams(sw / 3, sw / 3);
paramsVideo = new ViewGroup.LayoutParams(sw, 0);//为了图片适配
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return xxxList.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return xxxList.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
class ViewHolder {
FlowLayout ll;
int flag;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder = null;
xxxBean huati = xxxList.get(position);
if (convertView == null
|| ((ViewHolder) convertView.getTag()).flag != position) {//第一个判断是优化listview加载速度及内存消耗,第二个判断是为了防止图片错位
holder = new ViewHolder();
holder.flag = position;
convertView = inflater.inflate(R.layout.xxx_item_layout, null);
holder.ll = (FlowLayout) convertView.findViewById(R.id.flowlaytou);
ImageBean video = xxx.getVideoImg();
if (video != null && video.getUrl() != null
&& !"".equals(video.getUrl().trim())) {
paramsVideo.height = video.getHeight() * sw / video.getWidth();
addVideoView(holder.ll, video.getUrl(), paramsVideo, inflater);
}
List<ImageBean> imgList = huati.getImgList();
if (imgList != null && imgList.size() > 0) {
for (int i = 0; i < imgList.size(); i++) {
addImageView(holder.ll, imgList.get(i).getUrl(), paramsImg,
inflater, imgList, i);
}
}
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
private void addVideoView(FlowLayout ll, final String url,
LayoutParams params, LayoutInflater inflater) {
ImageView v = (ImageView) inflater.inflate(
R.layout.yyy_image_layout, null);//这个layout里面就只有一个imageview空间,特别简单
v.setLayoutParams(params);
ImageUtil.display(url, v);
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//这里的点击事件也完全没有问题,不会错位,不会点击失效
}
});
ll.addView(v);
}
private void addImageView(FlowLayout ll, String url, LayoutParams params,
LayoutInflater inflater) {
// TODO Auto-generated method stub
ImageView v = (ImageView) inflater.inflate(
R.layout.weixiu_image_layout, null);
v.setLayoutParams(params);
ImageUtil.display(url, v);
v.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//这里的点击事件也完全没有问题,不会错位,不会点击失效
} }); ll.addView(v); } }
至此,就就结束了,希望可以帮到一部分人。
Mikel