高级UI:自定义标签流水布局
来源:互联网 发布:js {}对象 编辑:程序博客网 时间:2024/06/01 10:23
#1 效果图
#2 需求
常见的搜索结果内容展示,大数据内容的标签分类展示,要有点击效果
#3 原理
字标签直接用xml布局添加或add进去,不用具体去计较,同时也使得每个item的扩展性较好;
最外层肯定是一个继承自ViewGroup的容器,我们要重新它的测量onMesure和onLayout方法,通过getChild来计算父控件的宽高和子控件的位置;
计算规则: 1 先在onMesure中获取父控件宽高和模式;
2 测量每个子控件的宽高,并累加后和父控件宽高对比;
3 当高于父控件宽度时,换行(每行View管理在一个List中,而所有行又用一个List管理,最后管理View的数据类型是:List<List<View>>),行高度累加;行宽、行高重新归0;若不高于父控件宽度时,行宽添加,继续遍历
4 注意:由于每个item的高度不一致,每次当前行高与item要做一次比较;父控件的宽要和每行的宽度比较
特殊情况:当刚好最后一个item此时又刚好换行,最后一个item做为一行,行宽高计算到父控件的宽高中去。
#3 自定义ViewGroup的代码
public class FlowLayout extends ViewGroup {
/**
* 用来保存每行views的列表
*/
private List<List<View>> mViewLinesList = new ArrayList<>();
/**
* 用来保存行高的列表
*/
private List<Integer> mLineHeights = new ArrayList<>();
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(),attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获取父容器为FlowLayout设置的测量模式和大小
int iWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int iHeightMode = MeasureSpec.getMode(heightMeasureSpec);
int iWidthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
int iHeightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
int measuredWith = 0;
int measuredHeight = 0;
int iCurLineW = 0;
int iCurLineH = 0;
if(iWidthMode == MeasureSpec.EXACTLY && iHeightMode == MeasureSpec.EXACTLY){
measuredWith = iWidthSpecSize;
measuredHeight = iHeightSpecSize;
}else{
int iChildWidth;
int iChildHeight;
int childCount = getChildCount();
List<View> viewList = new ArrayList<>();
for(int i = 0 ; i < childCount ; i++){
View childView = getChildAt(i);
measureChild(childView, widthMeasureSpec,heightMeasureSpec);
MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();
iChildWidth = childView.getMeasuredWidth() + layoutParams.leftMargin +
layoutParams.rightMargin;
iChildHeight = childView.getMeasuredHeight() + layoutParams.topMargin +
layoutParams.bottomMargin;
if(iCurLineW + iChildWidth > iWidthSpecSize){
/**1、记录当前行的信息***/
//1、记录当前行的最大宽度,高度累加
measuredWith = Math.max(measuredWith,iCurLineW);
measuredHeight += iCurLineH;
//2、将当前行的viewList添加至总的mViewsList,将行高添加至总的行高List
mViewLinesList.add(viewList);
mLineHeights.add(iCurLineH);
/**2、记录新一行的信息***/
//1、重新赋值新一行的宽、高
iCurLineW = iChildWidth;
iCurLineH = iChildHeight;
// 2、新建一行的viewlist,添加新一行的view
viewList = new ArrayList<View>();
viewList.add(childView);
}else{
// 记录某行内的消息
//1、行内宽度的叠加、高度比较
iCurLineW += iChildWidth;
iCurLineH = Math.max(iCurLineH, iChildHeight);
// 2、添加至当前行的viewList中
viewList.add(childView);
}
/*****3、如果正好是最后一行需要换行**********/
if(i == childCount - 1){
//1、记录当前行的最大宽度,高度累加
measuredWith = Math.max(measuredWith,iCurLineW);
measuredHeight += iCurLineH;
//2、将当前行的viewList添加至总的mViewsList,将行高添加至总的行高List
mViewLinesList.add(viewList);
mLineHeights.add(iCurLineH);
}
}
}
// 最终目的
setMeasuredDimension(measuredWith,measuredHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left,top,right,bottom;
int curTop = 0;
int curLeft = 0;
int lineCount = mViewLinesList.size();
for(int i = 0 ; i < lineCount ; i++) {
List<View> viewList = mViewLinesList.get(i);
int lineViewSize = viewList.size();
for(int j = 0; j < lineViewSize; j++){
View childView = viewList.get(j);
MarginLayoutParams layoutParams = (MarginLayoutParams) childView.getLayoutParams();
left = curLeft + layoutParams.leftMargin;
top = curTop + layoutParams.topMargin;
right = left + childView.getMeasuredWidth();
bottom = top + childView.getMeasuredHeight();
childView.layout(left,top,right,bottom);
curLeft += childView.getMeasuredWidth() + layoutParams.leftMargin
+ layoutParams.rightMargin;
}
curLeft = 0;
curTop += mLineHeights.get(i);
}
mViewLinesList.clear();
mLineHeights.clear();
}
public interface OnItemClickListener{
void onItemClick (View v, int index);
}
public void setOnItemClickListener(final OnItemClickListener listener){
int childCount = getChildCount();
for(int i = 0 ; i < childCount ; i++){
View childView = getChildAt(i);
final int finalI = i;
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(v, finalI);
}
});
}
}
}
#4 Demo地址
http://download.csdn.net/detail/baopengjian/9864922
- 高级UI:自定义标签流水布局
- UICollectionView自定义流水布局
- 自定义流水布局(实现相册功能)
- 流水布局UICollectionView初级的自定义
- TagGroup自定义标签布局
- IOS UI 自定义navigationBar布局
- JSP自定义标签学习(高级)
- JSP自定义标签学习(高级)
- 安卓布局UI高级技巧
- 自定义标签布局(流布局)
- UI - 自定义MJRefresh动画 , 自定义布局
- New UI-<ViewStub>标签延时加载布局
- 关于Android UI布局标签收藏
- Android UI高级之自定义控件
- ios开发 UI高级 自定义表情键盘
- 仿书旗小说关键词UI (自定义布局)
- ios开发-UI-自定义Tabbar 图书布局
- iOS-UICollectionViewFlowLayout 流水布局
- SU2 CFD代码阅读
- PowerDesigner 将数据库表结构生成物理数据模型(.pdm)
- QImage 与 cv::Mat 之间的相互转换
- tcp传输控制协议
- JAVA 八大基本类型
- 高级UI:自定义标签流水布局
- PHP中const与define的不同
- 微信jssdk上传多图的问题
- Activity生命周期(图文版)便于理解,记忆!
- Android中使用opengl es2.0基础(3)-正方体绘制
- Spark做数据分析:输入法性能指标分析
- 鹏鹏的Altium Designer快捷方式技巧--库文件的制作
- lintcode 合并区间
- JavaScript的数组实现队列与堆栈的方法