您的位置:首页 > 其它

自定义ViewGroup实现流式布局

2016-09-13 15:50 344 查看
第一次写博客,感觉有点小激动呢!

看效果:



是根据match_zhang大神的流式布局的思路,然后自己实现的,其中onLayout方法和match_zhang大神的不一样。

大体思路:

1.测绘onMeasure;

2.摆放子控件 onLayout;

详细的match_zhang说的很详细了,我就不多说了。

因为受到某人(数学老师,谁说数学没用的)的启发,为什么onMeasure的时候明明已经计算出了行高,每个child对应的位置,何不保存起来呢,所以我新增了

保存子控件左上角坐标的List:

private List<Point> viewPoints = new ArrayList<>();


保存子控件的坐标列表有了,那么重新修改onMeasure方法代码,测绘和定位一起做了,为了onLayout做准备

<pre name="code" class="java">    //在onMeasure里,测量所有子View的宽高,以及确定Viewgroup自己的宽高。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取系统传递过来测量出的宽度 高度,以及相应的测量模式。
//如果测量模式为 EXACTLY( 确定的dp值,match_parent),则可以调用setMeasuredDimension()设置,
//如果测量模式为 AT_MOST(wrap_content),则需要经过计算再去调用setMeasuredDimension()设置
int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);
int heigtMode = MeasureSpec.getMode(heightMeasureSpec);
int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);
int widthMode = Measu
4000
reSpec.getMode(widthMeasureSpec);

//计算宽度 高度 //wrap_content测量模式下会使用到:
int maxLineWidth = 0;
int totalHeight = 0;
//当前行高,宽
int curLineHeight = 0;
int curLineWidth = 0;

for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
//先测量子布局的宽高
measureChild(child, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams mlp = (MarginLayoutParams) child.getLayoutParams();
int childWidth = child.getMeasuredWidth() + mlp.leftMargin + mlp.rightMargin;
int childHeight = child.getMeasuredHeight() + mlp.topMargin + mlp.bottomMargin;
//换行 当前行宽+需要放置的child宽度小于最大行宽,换行
if (curLineWidth + childWidth > widthMeasure - getPaddingLeft() - getPaddingRight()) {
//通过比较 当前行宽 和以前存储的最大行宽,得到最新的最大行宽,用于设置父控件的宽度
maxLineWidth = Math.max(curLineWidth, maxLineWidth);
//父控件的高度增加了,为当前高度+当前行的高度
totalHeight = totalHeight + curLineHeight;
//重置当前的行宽和行高
curLineHeight = childHeight;
curLineWidth = childWidth;

//记录左上角坐标
//换行坐标从下一行开始计算,必须等totalHeight设置完毕在初始化坐标
Point point = new Point(mlp.leftMargin + getPaddingLeft(), totalHeight + getPaddingTop() + mlp.topMargin);
viewPoints.add(i, point);
} else {//摆放在同一行
//记录左上角坐标
Point point = new Point(getPaddingLeft()+curLineWidth + mlp.leftMargin, getPaddingTop() + totalHeight + mlp.topMargin);
viewPoints.add(i, point);

//不换行:叠加当前行宽 和 比较当前行高:
curLineWidth = curLineWidth + childWidth;
curLineHeight = Math.max(curLineHeight, childHeight);
}
//如果已经是最后一个View,要比较当前行的 宽度和最大宽度,叠加一共的高度
if (i == getChildCount() - 1) {
maxLineWidth = Math.max(maxLineWidth, curLineWidth);
totalHeight = totalHeight + curLineHeight;
}
}
//适配padding,如果是wrap_content,则除了子控件本身占据的大小+pidding
setMeasuredDimension(widthMode != MeasureSpec.EXACTLY ? maxLineWidth + getPaddingLeft() + getPaddingRight() : widthMeasure,
heigtMode != MeasureSpec.EXACTLY ? totalHeight + getPaddingTop() + getPaddingBottom() : heightMeasure);
}



注意:当最后一个child测量高度时,totalHeight=totalHeight+curLineHeight;如果加child的高度,那么碰到最后一行行高测量错误的情况:



不能忘记重写generateLayoutParams是子控件支持margin属性:

@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}


因为在onMeasure中保存子控件的顶点坐标,那么onLayout中代码就相对比较简单了:

@Override
protected void onLayout(boolean change, int l, int t, int r, int b) {
for (int i = 0; i < getChildCount(); i++) {
Point p = viewPoints.get(i);
View child = getChildAt(i);
int cl = p.x;
int cr = cl + child.getMeasuredWidth();
int ct = p.y;
int cb = ct + child.getMeasuredHeight();
child.layout(cl, ct, cr, cb);
}
}


好了,附上布局文件activity_main(本人比较懒,在match_zhang大神基础上面修改的):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.baoying.flowlayoutdemo.FlowLayout
android:background="#00c4ff"
android:padding="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="有padding"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#ff7700"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="流式"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#ff7700"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Java"
android:padding="15dp"
android:layout_margin="2dp"
android:background="#ff7700"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RxJava"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#00ff44"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:padding="5dp"
android:background="#ff7700"
android:text="CardView" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="OKHttp"
android:padding="25dp"
android:layout_margin="2dp"
android:background="#ff0008"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:padding="5dp"
android:background="#d66f16"
android:text="TabLayout" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="2dp"
android:padding="5dp"
android:background="#00aeff"
android:text="FloatActionBar" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ViewPager"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#393cff"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AsynkTask"
android:padding="35dp"
android:layout_margin="2dp"
android:background="#ff6f00"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="群英传"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#048899"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="padding"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#8800ff"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="padding"
android:padding="5dp"
android:layout_margin="2dp"
android:background="#ff8316"/>

</com.baoying.flowlayoutdemo.FlowLayout>
</LinearLayout>


完整demo地址:http://download.csdn.net/detail/qq1012692771/9629963

参考:http://blog.csdn.net/zxt0601/article/details/50533658
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: