自定义瀑布流控件WaterfallFlowLayout
来源:互联网 发布:java从小白到大牛 编辑:程序博客网 时间:2024/05/31 06:23
效果如下图所示:
实现效果:每个子项的宽度相同高度可能不同的布局
实现思路:
1.由于项宽度相同,则高度需要根据图片比例进行计算得出
2.用一个数组来存储每一列的总高度,将子控件添加到总高度最小的那一列的后面
3.通过onMeasure()方法计算出控件的高度,控件的高度为所有列高中最大的值,并自定义LayoutParams类,将子控件的left,top,right,bottom封装到layoutParams参数中,以便在onLayout方法中获取参数对子控件进行布局,最后通过setMeasuredDimension()方法来设置控件测量大小
4.在onLayout()方法中对子控件进行布局
一.自定义控件代码
public class WaterfallFlowLayout extends ViewGroup { private int column = 4;//显示的列数 private int horizontalSpace=10;//列间距 private int verticalSpace=10;//行间距 private int childWidth;//子控件的宽度 private int[] columnHeight=new int[column];//存储每一列的高度 public WaterfallFlowLayout(Context context) { this(context,null); } public WaterfallFlowLayout(Context context, AttributeSet attrs) { this(context, attrs,0); } public WaterfallFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.WaterfallFlowLayout); column=typedArray.getInteger(R.styleable.WaterfallFlowLayout_column,3); horizontalSpace=typedArray.getDimensionPixelSize(R.styleable.WaterfallFlowLayout_horizontalSpace,0); verticalSpace=typedArray.getDimensionPixelSize(R.styleable.WaterfallFlowLayout_verticalSpace,0); typedArray.recycle(); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MyLayoutParams(getContext(),attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //测量之后的宽度高度 int newWidth = 0; int newHeight = 0; if (widthMode == MeasureSpec.EXACTLY) { newWidth = widthSize; newHeight = heightSize; } else { //根据子控件的高度宽度测量出自身的宽高 measureChildren(widthMeasureSpec,heightMeasureSpec); //计算子控件的宽度 childWidth = (widthSize-(column-1)*horizontalSpace) / column; int childNum = getChildCount(); if (childNum < column) { newWidth = childWidth * childNum; } else { newWidth = widthSize; } for (int i = 0; i < childNum; i++) { View childView = getChildAt(i); //根据子控件的宽度计算出子控件应该显示的高度(需要等比例缩放) int width=childView.getMeasuredWidth(); int height=childView.getMeasuredHeight(); float scale= (float) (height*1.0 / width); int childHeight = (int) (childWidth *scale); //获取所有列当中高度最小的位置,放置子控件 int column=getMinHeight(); MyLayoutParams params= (MyLayoutParams) childView.getLayoutParams(); params.left=column*(childWidth+horizontalSpace); params.top=columnHeight[column]+verticalSpace; params.right=params.left+childWidth; params.bottom=params.top+childHeight; //对添加的列的高度进行累加 columnHeight[column]+=childHeight+verticalSpace; } newHeight=getMaxHeight();//获取整个列中最大值 } setMeasuredDimension(newWidth, newHeight); } //获取所有行中列高度最小的位置 private int getMinHeight(){ int minColumn=0; for(int i=1;i<columnHeight.length;i++){ if(columnHeight[i]<columnHeight[minColumn]){ minColumn=i; } } return minColumn; } //获取最大的高度 private int getMaxHeight(){ int maxHeight=columnHeight[0]; for(int i=1;i<columnHeight.length;i++){ if(columnHeight[i]>maxHeight){ maxHeight=columnHeight[i]; } } return maxHeight; } private void clearTop() { for (int i = 0; i < columnHeight.length; i++) { columnHeight[i] = 0; } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //对子控件进行布局 int childNum=getChildCount(); clearTop(); for(int i=0;i<childNum;i++){ View childView=getChildAt(i); MyLayoutParams params= (MyLayoutParams) childView.getLayoutParams(); childView.layout(params.left,params.top,params.right,params.bottom); } } public static class MyLayoutParams extends ViewGroup.LayoutParams{ public int left; public int top; public int right ; public int bottom ; public MyLayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } }
二.布局中使用
<ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.qdq.uidemo.WaterfallFlowLayout android:layout_width="wrap_content" android:layout_height="match_parent" app:horizontalSpace="5dp" app:verticalSpace="5dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/one" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/two" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/one" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/one" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/one" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" android:src="@drawable/one" /> </com.example.qdq.uidemo.WaterfallFlowLayout> </ScrollView>
三自定义属性文件代码
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="WaterfallFlowLayout"> <attr name="column" format="integer"/> <attr name="horizontalSpace" format="dimension"/> <attr name="verticalSpace" format="dimension"/> </declare-styleable></resources>
注意:本例中计算比例存在问题,当图片宽高大于屏幕宽高时,通过getMeasuredWidth()获取的宽度为屏幕宽度并非图片真实宽度,获取的高度也一样,导致比例计算不正确,导致显示异常
阅读全文
0 0
- 自定义瀑布流控件WaterfallFlowLayout
- WaterfallFlowLayout瀑布流用重写UICollectionViewFlowLayout类实现
- ios自定义瀑布流控件
- android自定义控件-瀑布流
- Android自定义控件StaggeredGridView-瀑布流效果的GridView
- Android自定义控件StaggeredGridView-瀑布流效果的GridView
- 自定义控件之瀑布流与水波纹实现
- iOS开发UI篇—自定义瀑布流控件(蘑菇街瀑布流)
- iOS开发UI篇—自定义瀑布流控件(蘑菇街瀑布流)
- iOS开发UI篇—自定义瀑布流控件(蘑菇街瀑布流)
- 自定义瀑布流
- 自定义瀑布流
- 自定义瀑布流
- 05.自定义瀑布流
- 自定义瀑布流
- 自定义瀑布流WaterPullLayout
- UICollectionView之控件瀑布流
- UICollectionView之控件瀑布流
- CentOS7 安装Docker
- Kotlin是什么?
- 欢迎使用CSDN-markdown编辑器
- 如何设计和生成游戏的激活码
- InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析
- 自定义瀑布流控件WaterfallFlowLayout
- Linux内核编译及添加系统调用
- Java ThreadPoolExecutor 线程池调度器
- 卸载安装、开机重启广播
- Bzoj3817:Sum
- 一些其他选择器
- form 转json最佳示例
- Python 算法实战系列:栈
- 重载与覆写的区别