[转载]【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); } }
至此,就就结束了,希望可以帮到一部分人。