android自定义viewgroup之我也玩瀑布流
Android 自定义 瀑布 ViewGroup
2023-09-11 14:18:00 时间
先看效果图吧,
继上一篇《android自定义viewgroup实现等分格子布局》中实现的布局效果,这里稍微有些区别,每个格子的高度不规则,就是传说的瀑布流布局,一般实现这种效果,要么用第三方控件,如果不是加载图片还可以直接写在xml中实现,不过代码会很多的;
下面我重写了viewgroup,实现 onMeasure,onLayout方法,动态设置每个布局的高度,这里有一个小的技巧,一般我们自定义的控件,嵌套在scrollview中显示不 全,这个问题也纠结我一小会,不过当你打开scrollview的源码,你会发现有一个地方,同时可以理解scrollview中嵌套 viewpager,gridview,listview时候会显示不全的问题
下面是自定义viewgroup的全部代码:
package com.allen.view;
import com.allen.mygridlayout.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.MeasureSpec;
/**
* @package:com.fumei.letao.views
* @author:Allen
* @email:jaylong1302@163.com
* @data:2013年11月26日 下午8:39:51
* @description:瀑布流视图
*/
public class WaterfullLayout extends ViewGroup {
final String tag = "balance";
// 列数
int columns = 2;
// 行数
int rows = 0;
// 边距
int margin = 10;
// 子视图数量
int count = 0;
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
public WaterfullLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.MyGridLayout);
columns = a.getInteger(R.styleable.MyGridLayout_numColumns, 2);
margin = (int) a.getInteger(R.styleable.MyGridLayout_itemMargin, 2);
}
}
public WaterfullLayout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
// TODO Auto-generated constructor stub
}
public WaterfullLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxChildWidth = 0;
mMaxChildHeight = 0;
count = getChildCount();
if (count == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
rows = count % columns == 0 ? count / columns : count / columns + 1;// 行数
int top[] = new int[columns];
for (int i = 0; i < rows; i++) {// 遍历行
for (int j = 0; j < columns; j++) {// 遍历每一行的元素
View child = this.getChildAt(i * columns + j);
if (child == null)
break;
ViewGroup.LayoutParams lp = child.getLayoutParams();
if (child.getVisibility() == GONE) {
continue;
}
child.measure(MeasureSpec.makeMeasureSpec(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
lp.height, MeasureSpec.AT_MOST));
top[j] += lp.height + margin;
mMaxChildWidth = Math.max(mMaxChildWidth,
child.getMeasuredWidth());
}
}
setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec),
resolveSize(getMax(top) + margin, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
int height = b - t;// 布局区域高度
int width = r - l;// 布局区域宽度
if (count == 0)
return;
int gridW = (width - margin * (columns + 1)) / columns;// 格子宽度
int gridH = 0;// 格子高度
int left = 0;
int top[] = new int[columns];
for (int i = 0; i < rows; i++) {// 遍历行
for (int j = 0; j < columns; j++) {// 遍历每一行的元素
View child = this.getChildAt(i * columns + j);
if (child == null)
return;
ViewGroup.LayoutParams lp = child.getLayoutParams();
child.measure(MeasureSpec.makeMeasureSpec(gridW,
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
lp.height, MeasureSpec.AT_MOST));
// 如果最后有一个对其的标志,为了底部对其
if (child.getTag() != null && child.getTag().equals(tag)) {
child.measure(MeasureSpec.makeMeasureSpec(gridW,
MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
getMax(top) - top[j], MeasureSpec.EXACTLY));
gridH = getMax(top) - top[j];
left = j * gridW + margin * (j + 1);
child.layout(left, top[j] + margin, left + gridW, top[j]
+ gridH);
break;
}
gridH = lp.height;
left = j * gridW + margin * (j + 1);
top[j] += margin;
child.layout(left, top[j], left + gridW, top[j] + gridH);
top[j] += gridH;
}
}
}
/** 计算整体布局高度,为了在嵌套在scrollview中能显示出来 */
private int getMax(int array[]) {
int max = array[0];
for (int i = 0; i < array.length; i++) {
if (max < array[i])
max = array[i];
}
return max;
}
}
相关文章
- Android 自定义控件开发入门(二)
- Android_(控件)使用自定义控件在屏幕中绘制一条虚线
- android 自定义gallerey并实现预览功能
- android开发之代码混淆
- Android绘图机制(三)——自定义View的实现方式以及半弧圆新控件
- Android开发之adb无法连接
- Android 中文 API (100) —— ScrollView
- Android:RecyclerView横向滑动+自定义滑动条
- Android GIS开发系列-- 入门季(8) Json与Geometry的相互转换
- Rockchip RK3588 Android SDK编译方法
- Android ListView + ArrayAdapter、SimpleAdapter、BaseAdapter实现列表
- Android 自定义View(二)绘制一个封闭多边形
- Android 自定义控件
- android 自定义栏
- android 11.0 系统Services(自定义服务) 添加jni方法
- Android 自定义ViewPager(仿蘑菇街欢迎页)
- Android 自定义ios样式的Switch开关
- android 7.0 8.1 9.0 10.0 添加自定义api(类) 给app调用
- 【Android Gradle 插件】自定义 Gradle 插件模块 ① ( 在 Module 模块中自定义 Gradle 插件 | 创建自定义插件类型模块 | 手动导入相关依赖 )
- 【Android 性能优化】应用启动优化 ( 启动白屏问题 | 应用启动时间测量 | 冷启动 | 热启动 | 应用启动时间计算源码分析 )
- 解决Android中No resource found that matches android:TextAppearance.Material.Widget.Button.Inverse问题
- Android系统解除USER版本无法进入Recovery模式限制
- android 输入法如何启动流程_Android输入法显示流程
- Android 自定义的验证码输入框(无光标),android版本10暂时不支持自定义粘贴