美文网首页
仿淘宝搜索历史界面(流式布局)

仿淘宝搜索历史界面(流式布局)

作者: remax1 | 来源:发表于2020-04-23 09:06 被阅读0次

    一 关于自定义viewGroup

    自定义viewGroup需要继承viewGroup,并重写抽象方法onLayout,负责子view位置的摆放。onMeasure()方法则完成对子view的测量过程,其中,对子view的测量涉及到MeasureSpec,包括父布局的MeasureSpec和子view的MeasureSpec。对子view的宽高测量完成后,相加即为viewGroup的宽高,再通过setMeasuredDimension()这个方法来保存测量好的宽高。
    

    二 关于MeasureSpec

    MeasureSpec代表一个32位int值,高2位代表SpecMode,低30位代码SpecSize,SpecMode是指测量模式,而SpecSize是指在某种测量模式下地规格地大小。

    SpecMode有三类,每一类都表示特殊的含义,如下所示。

    UNSPECIFIED

    父容器不对View有任何限制,要多大给多大,这种情况一般用于系统内部,表示一种测量状态。

    EXACTLY

    父容器以及检测出View所需要的大小,这个时候View的最终大小就是SpecSize所指定的值。它对应于LayoutParams中的match_parent和具体数值这两种模式。

    AT_MOST

    父容器指定了一个可用大小即SpecSize,View的大小不能大于这个值,具体是什么要看不同View的具体实现。它对应于LayoutParams中的wrap_content。

    三 关于流式布局Measure流程

    1.遍历所有的子view,根据父布局的MeasureSpec还有子view的LayoutParams 算出子view的MesureSpec

    
    LayoutParams childLP = childView.getLayoutParams();
    
    int childWidthMesureSpec =getChildMeasureSpec(widthMeasureSpec,paddingLeft+paddingRight,childLP.width);
    
    int childHeightMesureSpec =getChildMeasureSpec(heightMeasureSpec,paddingBottom+paddingTop,childLP.height);
    
    childView.measure(childWidthMesureSpec,childHeightMesureSpec);
    
    

    2.通过宽度来判断是否需要换行,通过换行后的每行的行高来获取整个viewGroup的行高

    如果宽度不够,则需换行

    
    if (childMesuredWidth + lineWidthUsed +mHorizontalSpacing > selfWidth){
    
    allLines.add(lineViews);
    
        lineHeights.add(lineHeight);
    
        //一旦换行,可以判断当前所需的宽高了
    
        parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed+mHorizontalSpacing);
    
        parentNeededHeight = parentNeededHeight + lineHeight +mVerticalSpacing;
    
        lineViews =new ArrayList<>();
    
        lineWidthUsed =0;
    
        lineHeight =0;
    
    }
    
    

    3.根据子View的度量结果,来重新度量自己ViewGroup

    作为一个ViewGroup,它自己也是一个View,它的大小也需要根据它的父亲给它提供的宽高来度量

    
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
    int realWidth = (widthMode == MeasureSpec.EXACTLY)? selfWidth:parentNeededWidth;
    
    int realHeight = (heightMode == MeasureSpec.EXACTLY)?selfHeight:parentNeededHeight;
    
    setMeasuredDimension(realWidth,realHeight);
    
    

    四 关于layout流程

    measure完成后,每个子view的宽高通过view.getMeasuredHeight/Width 来获得,只需算出距离viewGroup左边和顶部的距离传入即可。

    
    int lineCount =allLines.size();
    
    int curL =0;
    
    int curT =0;
    
    for (int i =0;i
    
    List lineViews =allLines.get(i);
    
        int lineHeight =lineHeights.get(i);
    
        for (int j =0;j
    
    View view = lineViews.get(j);
    
            int left = curL;
    
            int top = curT;
    
            int bottom = top + view.getMeasuredHeight();
    
            int right = left + view.getMeasuredWidth();
    
            view.layout(left,top,right,bottom);
    
            curL = right +mHorizontalSpacing;
    
        }
    
    curL =0;
    
        curT = curT + lineHeight +mVerticalSpacing;
    
    

    五 关于源代码FlowLayout源代码

    
    /**
    
    * created by lxx
    
    * on 2020/4/22
    
    */
    
    public class FlowLayoutextends ViewGroup {
    
    private int mHorizontalSpacing =dp2px(16); //每个item横向间距
    
        private int mVerticalSpacing =dp2px(8); //每个item横向间距
    
        private  List>allLines ; // 记录所有的行,一行一行的存储
    
        private  ListlineHeights =new ArrayList<>(); // 记录每一行的行高
    
        boolean isMeasuredOver =false;
    
        public FlowLayout(Context context) {
    
    super(context);
    
        }
    
    public FlowLayout(Context context, AttributeSet attrs) {
    
    super(context, attrs);
    
        }
    
    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    
    super(context, attrs, defStyleAttr);
    
        }
    
    @Override
    
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    initMeasureParams();
    
            int childCount = getChildCount();
    
            int paddingLeft = getPaddingLeft();
    
            int paddingRight = getPaddingRight();
    
            int paddingTop = getPaddingTop();
    
            int paddingBottom = getPaddingBottom();
    
            int selfWidth = MeasureSpec.getSize(widthMeasureSpec);  //ViewGroup解析的宽度
    
            int selfHeight = MeasureSpec.getSize(heightMeasureSpec); // ViewGroup解析的高度
    
            List lineViews =new ArrayList<>(); //保存一行中的所有的view
    
            int lineWidthUsed =0; //记录这行已经使用了多宽的size
    
            int lineHeight =0; // 一行的行高
    
            int parentNeededWidth =0;  // measure过程中,子View要求的父ViewGroup的宽
    
            int parentNeededHeight =0; // measure过程中,子View要求的父ViewGroup的高
    
            for (int i =0;i
    
    View childView = getChildAt(i);
    
                LayoutParams childLP = childView.getLayoutParams();
    
                int childWidthMesureSpec =getChildMeasureSpec(widthMeasureSpec,paddingLeft+paddingRight,childLP.width);
    
                int childHeightMesureSpec =getChildMeasureSpec(heightMeasureSpec,paddingBottom+paddingTop,childLP.height);
    
                childView.measure(childWidthMesureSpec,childHeightMesureSpec);
    
                //获取子view的宽高
    
                int childMesuredWidth = childView.getMeasuredWidth();
    
                int childMesuredHeight = childView.getMeasuredHeight();
    
                //通过宽度来判断是否需要换行,通过换行后的每行的行高来获取整个viewGroup的行高
    
    //如果宽度不够,则需换行
    
                if (childMesuredWidth + lineWidthUsed +mHorizontalSpacing > selfWidth){
    
    allLines.add(lineViews);
    
                    lineHeights.add(lineHeight);
    
                    //一旦换行,可以判断当前所需的宽高了
    
                    parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed+mHorizontalSpacing);
    
                    parentNeededHeight = parentNeededHeight + lineHeight +mVerticalSpacing;
    
                    lineViews =new ArrayList<>();
    
                    lineWidthUsed =0;
    
                    lineHeight =0;
    
                }
    
    // view 是分行layout的,所以要记录每一行有哪些view,这样可以方便layout布局
    
                lineViews.add(childView);
    
                lineWidthUsed = lineWidthUsed + childMesuredWidth +mHorizontalSpacing;
    
                lineHeight = Math.max(lineHeight,childMesuredHeight);
    
                //childview 最后一行
    
                if (i == childCount -1){
    
    lineHeights.add(lineHeight);
    
                    allLines.add(lineViews);
    
                    parentNeededWidth = Math.max(parentNeededWidth,lineWidthUsed );
    
                    parentNeededHeight += lineHeight;
    
                }
    
    //根据子View的度量结果,来重新度量自己ViewGroup
    
    // 作为一个ViewGroup,它自己也是一个View,它的大小也需要根据它的父亲给它提供的宽高来度量
    
                int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    
                int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    
                int realWidth = (widthMode == MeasureSpec.EXACTLY)? selfWidth:parentNeededWidth;
    
                int realHeight = (heightMode == MeasureSpec.EXACTLY)?selfHeight:parentNeededHeight;
    
                setMeasuredDimension(realWidth,realHeight);
    
                isMeasuredOver =true;
    
            }
    
    }
    
    private void initMeasureParams() {
    
    allLines =new ArrayList<>();
    
            lineHeights =new ArrayList<>();
    
        }
    
    @Override
    
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
    int lineCount =allLines.size();
    
            int curL =0;
    
            int curT =0;
    
            for (int i =0;i
    
    List lineViews =allLines.get(i);
    
                int lineHeight =lineHeights.get(i);
    
                for (int j =0;j
    
    View view = lineViews.get(j);
    
                    int left = curL;
    
                    int top = curT;
    
                    int bottom = top + view.getMeasuredHeight();
    
                    int right = left + view.getMeasuredWidth();
    
                    view.layout(left,top,right,bottom);
    
                    curL = right +mHorizontalSpacing;
    
                }
    
    curL =0;
    
                curT = curT + lineHeight +mVerticalSpacing;
    
            }
    
    }
    
    public static int dp2px(int dp) {
    
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    
        }
    
    }
    
    

    六 项目运行截图

    296EC3A46E1EEFD584E9E00A73C164CF.jpg

    github项目地址:https://github.com/doubizhu/flowlayout

    有用请给我star qaq谢谢大家。

    相关文章

      网友评论

          本文标题:仿淘宝搜索历史界面(流式布局)

          本文链接:https://www.haomeiwen.com/subject/rxtoihtx.html