您当前的位置: 首页 >  ui

命运之手

暂无认证

  • 3浏览

    0关注

    747博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【高级UI】【006】测量和布局实战,流式布局

命运之手 发布时间:2021-10-12 15:17:09 ,浏览量:3

前言

前面我们已经讲解过measure和layout的实际调用流程

这节我们通过一个案例,具体演示这些方法是如何使用的

接下来我们要实现的是一个综合了瀑布流布局和流式布局功能的自定义布局

瀑布流布局和流式布局的大概效果,就是有若干元素,它们能够自动按行排列,一行空间不够就自动切换到下一行

区别是,瀑布流布局(FallsLayout)一般是等宽的,而流式布局(FlowLayout)一般是等高的

FallsLayout FlowLayout 而我们的布局是支持既不等高也不等宽的元素的

这样的布局没有瀑布流布局和流式布局好看,但我们只要控制子元素的宽高固定,它就可以立刻呈现这两种布局的效果

所以我们的布局是一个万能的流布局

实现思路

每个元素都有上下左右四个顶点,我们分别用两个List,来记录这些顶点的x,y坐标值,并按从小到大排序

当我们加入一个新元素时,其左上角一定是和其中某个坐标对齐的

我们只要按照从小到大的顺序,遍历所有[x, y]的组合,尝试将新元素放到该位置

如果该元素的范围不与已经添加的所有元素重合,则说明该位置就是可用的位置,将新元素摆放到这里即可

要注意的是,控件是有padding和margin的,measure和layout时要考虑这些细节

关键代码


	package com.easing.commons.android.ui.control.layout;
	
	import android.content.Context;
	import android.util.AttributeSet;
	import android.view.View;
	import android.view.ViewGroup;
	
	import com.easing.commons.android.app.CommonActivity;
	import com.easing.commons.android.manager.Dimens;
	import com.easing.commons.android.ui.adapter.ViewAdapter;
	import com.easing.commons.android.value.measure.Rect;
	
	import java.util.LinkedList;
	
	//瀑布流布局(元素从左到右,从上到下,见缝就插,没有行的概念)
	@SuppressWarnings("all")
	public class FallsLayout extends ViewGroup {
	
	    protected CommonActivity context;
	
	    protected ViewAdapter adapter;
	
	    protected int margin = Dimens.toPx(0);
	
	    //记录所有的边界点
	    protected final Object lock = new Object();
	    protected final LinkedList xList = new LinkedList();
	    protected final LinkedList yList = new LinkedList();
	
	    //已经使用的区域
	    protected final LinkedList usedRects = new LinkedList();
	
	    //父级宽度
	    protected int parentWidth;
	
	    public FallsLayout(Context context) {
	        super(context, null);
	    }
	
	    public FallsLayout(Context context, AttributeSet attributeSet) {
	        super(context, attributeSet);
	        init(context, attributeSet);
	    }
	
	    //初始化
	    protected void init(Context context, AttributeSet attributeSet) {
	        this.context = (CommonActivity) context;
	    }
	
	    @Override
	    protected LayoutParams generateDefaultLayoutParams() {
	        MarginLayoutParams lp = new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
	        lp.setMargins(margin, margin, margin, margin);
	        return lp;
	    }
	
	    @Override
	    public LayoutParams generateLayoutParams(AttributeSet attrs) {
	        MarginLayoutParams lp = new MarginLayoutParams(getContext(), attrs);
	        return lp;
	    }
	
	    @Override
	    protected LayoutParams generateLayoutParams(LayoutParams p) {
	        MarginLayoutParams lp = new MarginLayoutParams(p);
	        return lp;
	    }
	
	    @Override
	    protected void onMeasure(int wSpec, int hSpec) {
	
	        //解析测量参数
	        int mode_w = MeasureSpec.getMode(wSpec);
	        int mode_h = MeasureSpec.getMode(hSpec);
	        int size_w = MeasureSpec.getSize(wSpec);
	        int size_h = MeasureSpec.getSize(hSpec);
	
	        //瀑布布局必须明确指定宽高
	        if (mode_w != MeasureSpec.EXACTLY)
	            throw new RuntimeException("FallsLayout must exactly specify width");
	        parentWidth = size_w;
	
	        //添加起始位置
	        xList.clear();
	        yList.clear();
	        usedRects.clear();
	        xList.add(getPaddingLeft());
	        yList.add(getPaddingTop());
	
	        //循环遍历子View,测量总尺寸
	        for (int i = 0; i             
关注
打赏
1654938663
查看更多评论
0.0540s