自定义viewGroup 实现 流式布局
2017-05-18 17:31
477 查看
首先看这篇文章时前 希望你看下http://blog.csdn.net/lmj623565791/article/details/38339817 这篇博客,学习一下简单的自定义viewGroup,如果这篇文章你看懂了,我想你就能直接写这个需求了.
不多说,先虑一下思路:有很多个view,然后一个一个放置到viewGroup中,如果每一个view不能够放下了,就换行。
看下原理图:
红色的是textview的margin 黑色的是viewGroup的padding。
接下来看下整体效果图:
然后看代码:
关于上面的代码我一点点解释
也就是获取viewGroup的测量方式和viewGroup的宽高
上述代码其实就是直接将初始化viewGroup的高度,因为始终要记住onMeasure只是计算宽度和高度!,然后每换一次行 curHeight就加一下textview的高度和margin.
上述代码和curHeight一样的,就是换一次行,然后curWidth重置为0,然后在加上viewGroup的padding。
上述代码基本可以说是onmeasure的核心代码,if判断也就是如果curWidth + TextView的宽度+ TextView的margin < viewgroup的宽度,这表明还能放下该textview,此时应该更新curwidth的值。然后判断下一个TextView(也就是i++)。如果else呢就表明大于viewGroup的宽度,此时应该将curwidth置为0,然后curheight需要加上TextView的margin和TextView的高度。(curHeight其实就是每一行的Height和viewGroup的padding).
这个行是非常关键的,就是当最后一个TextView测量完之后,我们需要加上这一行的高度!!!对于为什么,你可以捋一下这个程序流程就知道了。如果不加的话,就不会显示最后一行数据。
好了,接下来看onLayout:
首先需要注意的是onLayout中的curHeight初始化是:
这根onMeasure不一样,因为还是那句话,onMeasure只是测量,而onLayout就是放置位置了,这时就是从上到下,从左到右了。
然后就是核心代码了:
思路:比较某一行是否能够放下该TextView 如果能,就直接放置,然后curwidth更新数据(加上放置的TextView的宽度和margin),最后i++(判断下一个TextView是否能够放下);如果不能放下,这就将curwidth重置为0,然后换行(curheight += TextView的高度 + TextView的上下margin)
然后这个实现了最后贴上整个自定义的ViewGroup:
最后附上源码下载地址:
http://download.csdn.net/detail/lmq121210/9845960
不多说,先虑一下思路:有很多个view,然后一个一个放置到viewGroup中,如果每一个view不能够放下了,就换行。
看下原理图:
红色的是textview的margin 黑色的是viewGroup的padding。
接下来看下整体效果图:
然后看代码:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); //测量ViewGroup的宽高 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); //ViewGroup的padding int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBott 4000 om(); int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); //当前宽度 int curWidth = 0; //当前高度 int curHeight = paddingTop + paddingBottom; //最大宽度 int widthMax = 0; for(int i = 0;i < getChildCount();){ View childView = getChildAt(i); measureChild(childView, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams(); int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); if(curWidth == 0 ){ curWidth = paddingLeft + paddingRight; curHeight += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin + childHeight; } if(curWidth + marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth <= widthSize){ //不换行 curWidth += marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth; i++; }else{ //换行 widthMax = Math.max(widthMax, curWidth); curWidth = 0; } //判断是否是最后一行 if(i == getChildCount()){ widthMax = Math.max(widthMax, curWidth); curHeight += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin + childHeight; } } setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : widthMax , heightMode == MeasureSpec.EXACTLY ? heightSize : curHeight); }
关于上面的代码我一点点解释
//测量模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); //测量ViewGroup的宽高 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec);
也就是获取viewGroup的测量方式和viewGroup的宽高
//初始化curHeight,加上viewGroup的上下padding; 注意: curHeight也就是最终要显示的高度 curHeight += parentBottom + parentTop;
上述代码其实就是直接将初始化viewGroup的高度,因为始终要记住onMeasure只是计算宽度和高度!,然后每换一次行 curHeight就加一下textview的高度和margin.
if(curWidth == 0 ){ curWidth = paddingLeft + paddingRight; curHeight += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin + childHeight; }
上述代码和curHeight一样的,就是换一次行,然后curWidth重置为0,然后在加上viewGroup的padding。
if(curWidth + marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth <= widthSize){ //不换行 curWidth += marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth; i++; }else{ //换行 widthMax = Math.max(widthMax, curWidth); curWidth = 0; }
上述代码基本可以说是onmeasure的核心代码,if判断也就是如果curWidth + TextView的宽度+ TextView的margin < viewgroup的宽度,这表明还能放下该textview,此时应该更新curwidth的值。然后判断下一个TextView(也就是i++)。如果else呢就表明大于viewGroup的宽度,此时应该将curwidth置为0,然后curheight需要加上TextView的margin和TextView的高度。(curHeight其实就是每一行的Height和viewGroup的padding).
//判断是否是最后一行 if(i == getChildCount()){ widthMax = Math.max(widthMax, curWidth); curHeight += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin + childHeight; }
这个行是非常关键的,就是当最后一个TextView测量完之后,我们需要加上这一行的高度!!!对于为什么,你可以捋一下这个程序流程就知道了。如果不加的话,就不会显示最后一行数据。
好了,接下来看onLayout:
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //获取ViewGroup的padding int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); //当前宽度; int curWidth = paddingLeft; //当前高度 int curHeight = paddingTop; for(int i = 0; i < getChildCount();){ View childView = getChildAt(i); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams(); int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); if(curWidth + paddingRight + marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth <= getWidth()){ //不换行 childView.layout(curWidth + marginLayoutParams.leftMargin, curHeight + marginLayoutParams.topMargin, curWidth + marginLayoutParams.leftMargin + childWidth, curHeight + marginLayoutParams.topMargin + childHeight); curWidth += marginLayoutParams.leftMargin + childWidth + marginLayoutParams.rightMargin; i ++; }else{ //换行 curHeight += marginLayoutParams.topMargin + childHeight + marginLayoutParams.bottomMargin; curWidth = paddingLeft; } } }
首先需要注意的是onLayout中的curHeight初始化是:
int curHeight = paddingTop;//
这根onMeasure不一样,因为还是那句话,onMeasure只是测量,而onLayout就是放置位置了,这时就是从上到下,从左到右了。
然后就是核心代码了:
int childHeight = childView.getMeasuredHeight(); if(curWidth + paddingRight + marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth <= getWidth()){ //不换行 childView.layout(curWidth + marginLayoutParams.leftMargin, curHeight + marginLayoutParams.topMargin, curWidth + marginLayoutParams.leftMargin + childWidth, curHeight + marginLayoutParams.topMargin + childHeight); curWidth += marginLayoutParams.leftMargin + childWidth + marginLayoutParams.rightMargin; i ++; }else{ //换行 curHeight += marginLayoutParams.topMargin + childHeight + marginLayoutParams.bottomMargin; curWidth = paddingLeft; }
思路:比较某一行是否能够放下该TextView 如果能,就直接放置,然后curwidth更新数据(加上放置的TextView的宽度和margin),最后i++(判断下一个TextView是否能够放下);如果不能放下,这就将curwidth重置为0,然后换行(curheight += TextView的高度 + TextView的上下margin)
然后这个实现了最后贴上整个自定义的ViewGroup:
package com.app.test.testflowproject;
import android.content.Context;
import android.location.GnssMeasurementsEvent;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by ${liumegnqiang} on 2017/5/18.
*/
public class FlowViewGroup extends ViewGroup {
public FlowViewGroup(Context context) {
super(context);
}
public FlowViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FlowViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//测量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//测量ViewGroup的宽高
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//ViewGroup的padding
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
//当前宽度
int curWidth = 0;
//当前高度
int curHeight = paddingTop + paddingBottom;
//最大宽度
int widthMax = 0;
for(int i = 0;i < getChildCount();){
View childView = getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
if(curWidth == 0 ){ curWidth = paddingLeft + paddingRight; curHeight += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin + childHeight; }
if(curWidth + marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth <= widthSize){ //不换行 curWidth += marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth; i++; }else{ //换行 widthMax = Math.max(widthMax, curWidth); curWidth = 0; }
//判断是否是最后一行 if(i == getChildCount()){ widthMax = Math.max(widthMax, curWidth); curHeight += marginLayoutParams.topMargin + marginLayoutParams.bottomMargin + childHeight; }
}
setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : widthMax ,
heightMode == MeasureSpec.EXACTLY ? heightSize : curHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//获取ViewGroup的padding
int<
bf00
/span> paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int paddingLeft = getPaddingLeft();
int paddingRight = getPaddingRight();
//当前宽度;
int curWidth = paddingLeft;
//当前高度
int curHeight = paddingTop;
for(int i = 0; i < getChildCount();){
View childView = getChildAt(i);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
int childWidth = childView.getMeasuredWidth();
int childHeight = childView.getMeasuredHeight();
if(curWidth + paddingRight + marginLayoutParams.rightMargin + marginLayoutParams.leftMargin + childWidth <= getWidth()){
//不换行
childView.layout(curWidth + marginLayoutParams.leftMargin,
curHeight + marginLayoutParams.topMargin,
curWidth + marginLayoutParams.leftMargin + childWidth,
curHeight + marginLayoutParams.topMargin + childHeight);
curWidth += marginLayoutParams.leftMargin + childWidth + marginLayoutParams.rightMargin;
i ++;
}else{
//换行
curHeight += marginLayoutParams.topMargin + childHeight + marginLayoutParams.bottomMargin;
curWidth = paddingLeft;
}
}
}
}
最后附上源码下载地址:
http://download.csdn.net/detail/lmq121210/9845960
相关文章推荐
- 自定义ViewGroup实现流式布局
- android 自定义ViewGroup实现流式布局过程
- 自定义ViewGroup实现流式布局
- ViewGroup2——自定义实现流式布局
- Android自定义ViewGroup实现流式布局
- 自定义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自定义自动换行的布局的实现(用于备忘)