自定义空间--瀑布流容器

效果就是添加图片, 图片会自动添加到最短的一列中。跟瀑布一样垂下来。  这里说一句   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

自定义空间--瀑布流容器的相关文章

自定义控件三部曲视图篇(三)——瀑布流容器WaterFallLayout实现

前言:只要在前行,梦想就不再遥远 系列文章: Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268 前面两节讲解了有关ViewGroup的onMeasure.onLayout的知识,这节我们深入性地探讨一下,如何实现经常见到的瀑布流容器,本节将实现的效果图如下: 从效果图中可以看出这里要完成的几个功能: 1.图片随机添加 2.在添加图片时,总是将新图片插入到当前最短的列中 3.每个Item后,

自定义UICollectionViewLayout之瀑布流

目标效果 因为系统给我们提供的 UICollectionViewFlowLayout 布局类不能实现瀑布流的效果,如果我们想实现 瀑布流 的效果,需要自定义一个 UICollectionViewLayout  类,实现瀑布流效果.效果如右图. 依赖工具: 我们需要一个图片大小和图片地址的Josn数据, 和 SDWebImage图片加载的第三方工具 RootViewController.m 1 #import "RootViewController.h" 2 #import "

iOS开发之窥探UICollectionViewController(三) --使用UICollectionView自定义瀑布流

上篇博客的实例是自带的UICollectionViewDelegateFlowLayout布局基础上来做的Demo, 详情请看<iOS开发之窥探UICollectionViewController(二) --详解CollectionView各种回调>.UICollectionView之所以强大,是因为其具有自定义功能,这一自定义就不得了啦,自由度非常大,定制的高,所以功能也是灰常强大的.本篇博客就不使用自带的流式布局了,我们要自定义一个瀑布流.自定义的瀑布流可以配置其参数: 每个Cell的边距

iOS开发UI篇—自定义瀑布流控件(蘑菇街实现)

iOS开发UI篇—自定义瀑布流控件(蘑菇街瀑布流) 一.简单说明 关于瀑布流 1.是使用UIScrollView实现的 2.刷新数据(reloadData)方法里面做哪些事情 3.layoutSubviews方法里面做哪些事情 4.模仿UItableView进行设计 完善: 瀑布流控件第一次显示到屏幕上的时候自动的向数据源索要数据,而不需要手动调用.这需要监听View的显示,View的显示有一个方法,叫做willMoveToSuperview:在该方法中直接刷新一次数据即可. 二.把自定义的瀑布

iOS开发UI篇—自定义瀑布流控件(接口设计)

iOS开发UI篇—自定义瀑布流控件(接口设计) 一.简单说明 1.关于瀑布流 电商应用要展示商品信息通常是通过瀑布流的方式,因为每个商品的展示图片,长度和商都都不太一样. 如果不用瀑布流的话,展示这样的格子数据,还有一种办法是使用九宫格. 但利用九宫格有一个缺点,那就是每个格子的宽高是一样的,如果一定要使用九宫格来展示,那么展示的商品图片可能会变形. 为了保证商品图片能够按照原来的宽高比进行展示,一般采用的是瀑布流的方式. 2.瀑布流的特点: 由很多的格子组成,但是每个格子的宽度和高速都是不确定

在 JQuery Mobile 中实现瀑布流图库布局

先来看在Windows系统的1080P显示器中显示的效果: 这个整合方式几乎没有现存的实例,是自己总结出来的方法,在此记录下来. 首先访问Masonry官网下载masonry.pkgd.min.js:http://masonry.desandro.com/ 将其整合到项目中,在页面中引入. 初始化id变量,让页面每次加载时的id都不同,避免 Ajax 加载时id重复造成难以察觉的错误. var id = "gallerycontent" + Guid.NewGuid(); 采用HTML

Android 自定义ViewGroup之实现FlowLayout-标签流容器

本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout,但不影响我对其的学习.和往常一样,主要还是想总结一下自定义ViewGroup的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.写代码之前,有几个是问题是我们先要弄清楚的: 1.什么是ViewGroup:从名字上来看,它可以被翻译为控件组,言外之意是ViewGroup内部包含了许

自定义实现带文字标题的瀑布流效果

在网上能找到的大部分资料中的瀑布流效果都是单纯的照片实现,现在我来实现一个带文字标题的.效果如下: 每个item都是由图片和文字标题两部分组成. 布局方式为ScrollView里面嵌套一个水平方向的LinearLayout,里面再嵌套两个竖直方向的LinearLayout,然后判断竖直方向的两个LinearLayout的高度,向比较低的那个Linearlayout里面添加item. 下面是代码 <ScrollView xmlns:android="http://schemas.androi

自定义UICollectionLayout布局 —— UIKit之学习UICollectionView记录一《瀑布流》

一.思路 思路一:比较每一行所有列的cell的高度,从上到下(也就是从第一行开始),从最短的开始计算,(记录下b的高度和索引,从开始计算,依次类推) 思路二:设置上.下.左.右间距和行间距.列间距及列数. 思路三:实现的重要的方法. 二.代码先行. 1.自定义layout类. //入口 #import <UIKit/UIKit.h> @protocol STRWaterLayoutDelegate; @interface STRWaterLayout : UICollectionViewLay