自定义ViewGroup实现流式布局
2016-09-13 15:50
344 查看
第一次写博客,感觉有点小激动呢!
看效果:
是根据match_zhang大神的流式布局的思路,然后自己实现的,其中onLayout方法和match_zhang大神的不一样。
大体思路:
1.测绘onMeasure;
2.摆放子控件 onLayout;
详细的match_zhang说的很详细了,我就不多说了。
因为受到某人(数学老师,谁说数学没用的)的启发,为什么onMeasure的时候明明已经计算出了行高,每个child对应的位置,何不保存起来呢,所以我新增了
保存子控件左上角坐标的List:
保存子控件的坐标列表有了,那么重新修改onMeasure方法代码,测绘和定位一起做了,为了onLayout做准备
注意:当最后一个child测量高度时,totalHeight=totalHeight+curLineHeight;如果加child的高度,那么碰到最后一行行高测量错误的情况:
不能忘记重写generateLayoutParams是子控件支持margin属性:
因为在onMeasure中保存子控件的顶点坐标,那么onLayout中代码就相对比较简单了:
好了,附上布局文件activity_main(本人比较懒,在match_zhang大神基础上面修改的):
完整demo地址:http://download.csdn.net/detail/qq1012692771/9629963
参考:http://blog.csdn.net/zxt0601/article/details/50533658
看效果:
是根据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
相关文章推荐
- 自定义ViewGroup实现流式布局
- 自定义viewGroup 实现 流式布局
- 自定义ViewGroup实现流式布局
- ViewGroup2——自定义实现流式布局
- Android自定义ViewGroup实现流式布局
- android 自定义ViewGroup实现流式布局过程
- 自定义ViewGroup实现流式布局(支持ViewGroup Padding, 子View margin,每行高度可以不一样)
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android自定义ViewGroup自动换行实现滑动任意布局及事件处理效果
- android之自定义ViewGroup和自动换行的布局的实现
- 自定义ViewGroup(3):自定义流式布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android自定义viewgroup实现等分格子布局
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- 基于ViewGroup自定义自动换行的布局的实现(用于备忘)