效果就是添加图片, 图片会自动添加到最短的一列中。跟瀑布一样垂下来。 这里说一句 onMeasure 和onLayout 会执行两次,如果在方法中去数据不是太好,可以再onChangeSize(),此方法在onMeasure后执行,可以获得控件测量的宽和高(getMeasureWidth、getMeasureHeight)不能获取到(getWidth,getHeight 这两个方法需要在onLayout执行后才有效);
<com.kallaite.rxjavademo.customcontrols.CustomImgLayout android:layout_width="match_parent" android:id="@+id/img_layout" android:layout_height="wrap_content" attrs:widthSpec="20" attrs:heightSpec="20" attrs:colums="3"></com.kallaite.rxjavademo.customcontrols.CustomImgLayout> 布局中有三个自定义属性,如果需要实现自定义属性,请看前面文章,自定义空间--自定义属性。 colums 表示有即列。 widthSpec: 表示左右边距, heightSpec : 表示上下边距。
package com.kallaite.rxjavademo.customcontrols; import android.content.Context;import android.content.res.TypedArray;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup; import com.kallaite.rxjavademo.R; /** * Created by yixijun on 17-8-7. */public class CustomImgLayout extends ViewGroup{ private int colums; private int heightSpec; private int widthSpec; private int top[]; private int childWidth; private int height; public CustomImgLayout(Context context) { this(context,null); } public CustomImgLayout(Context context, AttributeSet attrs) { this(context, attrs,0); } public CustomImgLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAttrs(context,attrs); } private void initAttrs(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomImgLayout); if (typedArray != null){ int colums = typedArray.getInteger(R.styleable.CustomImgLayout_colums, -1); int heightSpec = typedArray.getInteger(R.styleable.CustomImgLayout_heightSpec, -1); int widthSpec = typedArray.getInteger(R.styleable.CustomImgLayout_widthSpec, -1); typedArray.recycle(); if (colums != -1){ this.colums = colums; } if (heightSpec != -1){ this.heightSpec = heightSpec; } if (widthSpec != -1){ this.widthSpec = widthSpec; } if (colums != -1){ top = new int[colums]; }else { top = new int[1]; } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); //去测量子控件的宽高 measureChildren(widthMeasureSpec,heightMeasureSpec); int childCount = getChildCount(); if (colums == -1){ colums = 1; } if (widthSpec == -1){ widthSpec = 0; } if (heightSpec == -1){ heightSpec = 0; } int wrapWidth; int wrapHeight; //每一个图片的宽度都是一样的,得到每一个图片的宽度 childWidth = (widthSize - widthSpec * (colums - 1)) / colums; if (childCount < colums){ wrapWidth = childCount * childWidth + (childCount - 1) * widthSpec; }else { wrapWidth = widthSize; } clearTop(); for (int i = 0; i < childCount; i++) { View childAt = getChildAt(i); //图片按照比例去缩放,这边通过缩放比例,得到控件测量的宽 height = childAt.getMeasuredHeight() * childWidth / childAt.getMeasuredWidth(); //得到数组中最小高度对应的索引 int minColum = getMinHeightColum(); //把控件放到最小高度的位置,保存高度。 top[minColum] += (heightSpec + height); } //数组中最高的数量就是此控件容器的高度 wrapHeight = getMaxHeight(); //此方法必须要执行,用来设置测量的参数,通过得到手动设置的宽高模式,来设置宽高属性,是自己测量到的,还是设置的。 setMeasuredDimension(widthMode == MeasureSpec.AT_MOST ? wrapWidth : widthSize,wrapHeight); } private int getMaxHeight() { int colum = 0; for (int i = 0; i < top.length; i++) { if (top[i] > top[colum]){ colum = i; } } return top[colum]; } private int getMinHeightColum() { int colum = 0; for (int i = 0; i < top.length; i++) { if (top[i] < top[colum]){ colum = i; } } return colum; } private void clearTop() { for (int i = 0; i < top.length; i++) { top[i] = 0; } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childCount = getChildCount(); clearTop(); for (int i = 0; i < childCount; i++) { View childAt = getChildAt(i); //得到图片的高度 int height = childAt.getMeasuredHeight() * childWidth / childAt.getMeasuredWidth(); //最小的高度索引,通过索引可以得到图片应该在第几列,知道在第几列就知道了图片的左边距离,和高度距离,左边距离和高度加上宽、高,就知道控件应该摆放的位置了。 int minColum = getMinHeightColum(); int left = minColum * (childWidth + widthSpec); int topDesc = top[minColum]; int rightDesc = left + childWidth; int buttomDesc = topDesc + height; //把宽高保存一下,因为高度是要叠加起来的 top[minColum] += heightSpec + height; childAt.layout(left,topDesc,rightDesc,buttomDesc); final int finalI = i; //对应的控件点击事件,可以知道点击的是第几张图片。 childAt.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (clickItem != null){ clickItem.clickItem(finalI); } } }); } } interface ClickItem{ void clickItem(int i); } private ClickItem clickItem; //设置点击事件的接口方法。 public void setClickItemListener(ClickItem mClickItem){ clickItem = mClickItem; }}
时间: 2024-08-07 14:25:38