Android自定义View之实现流式布局

Android自定义View之实现流式布局,第1张

概述Android自定义View之实现流式布局运行效果流式布局把子控件从左到右摆放,如果一行放不下,自动放到下一行自定义布局流程1.自定义属性:声明,设置,解析获取自定义值在attr.xml中声明2.测量:在onMeasure方法测量自身的宽高和child的宽高3.布局:在onLayout方法里面根据

AndroID自定义view之实现流式布局运行效果

流式布局
把子控件从左到右摆放,如果一行放不下,自动放到下一行自定义布局流程
1. 自定义属性:声明,设置,解析获取自定义值 在attr.xml中声明
2. 测量:在onMeasure 方法测量自身的宽高和child的宽高
3. 布局:在onLayout方法里面根据自己的规则来确定children的位置
4. 绘制:onDraw
5. 处理layoutParams
6. 触摸反馈:滑动事件代码实现
属性定义
<?xml version="1.0" enCoding="utf-8"?><resources>    <declare-styleable name="FlowLayout">        <attr name="androID:gravity"/>        <attr name="androID:horizontalSpacing" format="dimension |reference"/>    </declare-styleable>    <declare-styleable name="FlowLayout_Layout">        <attr name="androID:layout_gravity"/>    </declare-styleable></resources>
布局文件
<?xml version="1.0" enCoding="utf-8"?>    <!--<ScrollVIEw xmlns:androID="http://schemas.androID.com/apk/res/androID"-->    <!--xmlns:app="http://schemas.androID.com/apk/res-auto"-->    <!--androID:layout_wIDth="match_parent"-->    <!--androID:layout_height="wrap_content"-->    <!--xmlns:tools="http://schemas.androID.com/tools">--><linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"xmlns:app="http://schemas.androID.com/apk/res-auto"xmlns:tools="http://schemas.androID.com/tools"androID:layout_wIDth="match_parent"androID:orIEntation="vertical"androID:layout_height="match_parent"><com.example.as.proj.myvIEwgroupdemo2.FlowLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"    xmlns:app="http://schemas.androID.com/apk/res-auto"    xmlns:tools="http://schemas.androID.com/tools"    androID:layout_wIDth="match_parent"    androID:layout_height="match_parent"    tools:context=".MainActivity">    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="55dp"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="match_parent"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="match_parent"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="90dp"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="85dp"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="45dp"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="75dp"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="60dp"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="85dp"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="100dp"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="85dp"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="85dp"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="65dp"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="100dp"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="75dp"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="80dp"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="300dp"        androID:text="生活不止眼前的苟且,还有诗和远方" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="小麻小儿郎呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="Hello hi ..." />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="你是谁呀" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="65dp"        androID:text="人在他在,塔亡人亡"        androID:layout_gravity="bottom"/>    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="生活不止眼前的苟且,还有诗和远方1" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="250dp"        androID:text="发电房" />    <button        androID:layout_wIDth="wrap_content"        androID:layout_height="wrap_content"        androID:text="这是结束" /></com.example.as.proj.myvIEwgroupdemo2.FlowLayout><!--</ScrollVIEw>--></linearLayout>

自定义view

package com.example.as.proj.myvIEwgroupdemo2;import androID.content.Context;import androID.content.res.TypedArray;import androID.util.AttributeSet;import androID.util.Log;import androID.vIEw.VIEw;import androID.vIEw.VIEwGroup;import java.util.ArrayList;import java.util.List;public class FlowLayout extends VIEwGroup {    public static final String TAG = "Zero";    private List<VIEw> lineVIEws; //每一行的子VIEw    private List<List<VIEw>> vIEws; //所有的行,一行一行的存储    private List<Integer> heights; //每一行的高度    public FlowLayout(Context context) {        this(context, null);    }    public FlowLayout(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public FlowLayout(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    private voID init(){        vIEws = new ArrayList<>();        lineVIEws = new ArrayList<>();        heights = new ArrayList<>();    }    @OverrIDe    protected voID onMeasure(int wIDthMeasureSpec, int heightmeasureSpec) {        super.onMeasure(wIDthMeasureSpec, heightmeasureSpec);        int wIDthMode = MeasureSpec.getMode(wIDthMeasureSpec);        int wIDthSize = MeasureSpec.getSize(wIDthMeasureSpec);        int heightmode = MeasureSpec.getMode(heightmeasureSpec);        int heightSize = MeasureSpec.getSize(heightmeasureSpec);        //记录当前行的宽和高        int linewidth = 0; //宽度是当前行子VIEw的宽度之和        int lineHeight = 0; //高度是当前行所有子VIEw中高度的最大值        //整个流式布局的宽度和高度        int flowlayoutWIDth = 0; //所有行中宽度的最大值        int flowlayoutHeight = 0; //所有行高度的累加        //初始化参数列表        init();        //遍历所有子VIEw,对子VIEw进行测量,分配到具体的行        int childCount = this.getChildCount();        for(int i = 0; i < childCount; i++){            VIEw child = this.getChildAt(i);            //测量子VIEw 获取当前子VIEw的测量宽高            measureChild(child, wIDthMeasureSpec, heightmeasureSpec);            //获取到当前子VIEw的测量的宽高            int chilDWIDth = child.getMeasureDWIDth();            int childHeight = child.getMeasuredHeight();            LayoutParams lp = (LayoutParams) child.getLayoutParams();            //看下当前的行的剩余宽度是否可以容纳下一个子VIEw            //如果放不下,换行 保存当前行所有的子VIEw,累加行高,当前的宽度 高度 置零            if(linewidth + chilDWIDth > wIDthSize){                //换行                vIEws.add(lineVIEws);                lineVIEws = new ArrayList<>();// 创建新的一行                flowlayoutWIDth = Math.max(flowlayoutWIDth, linewidth);                flowlayoutHeight += lineHeight;                heights.add(lineHeight);                linewidth = 0;                lineHeight = 0;            }            lineVIEws.add(child);            linewidth += chilDWIDth;            if(lp.height != LayoutParams.MATCH_PARENT){                //暂时先不要处理layout_height=match_parent                lineHeight = Math.max(lineHeight, childHeight);            }            Log.i(TAG, "onMeasure: " + lineHeight);            if(i == childCount - 1){                //最后一行                flowlayoutHeight += lineHeight;                flowlayoutWIDth = Math.max(flowlayoutWIDth, linewidth);                heights.add(lineHeight);                vIEws.add(lineVIEws);            }        }        //重新测量一次layout_height = match_parent        remeasureChild(wIDthMeasureSpec, heightmeasureSpec);        setMeasuredDimension(wIDthMode == MeasureSpec.EXACTLY ? wIDthSize : flowlayoutWIDth,                heightmode == MeasureSpec.EXACTLY ? heightSize : flowlayoutHeight);    }    private voID remeasureChild(int wIDthMeasureSpec, int heightmeasureSpec){        int linesize = vIEws.size();        for(int i = 0; i < linesize; i++){            int lineHeight = heights.get(i); //每一行行高            Log.i(TAG, "remeasureChile: " + lineHeight);            List<VIEw> lineVIEws = vIEws.get(i); //每一行的子VIEw            int size = lineVIEws.size();            for(int j = 0; j < size; j++){                VIEw child = lineVIEws.get(j);                LayoutParams lp = (LayoutParams) child.getLayoutParams();                if(lp.height == LayoutParams.MATCH_PARENT){                    int chilDWIDthSpec = getChildMeasureSpec(wIDthMeasureSpec, 0, lp.wIDth);                    int childHeightSpec = getChildMeasureSpec(heightmeasureSpec, 0, lineHeight);                    child.measure(chilDWIDthSpec, childHeightSpec);                }            }        }    }    @OverrIDe    protected voID onLayout(boolean changed, int l, int t, int r, int b) {        int lineCount = vIEws.size();        int currX = 0;        int currY = 0;        for (int i = 0; i < lineCount; i++){            //大循环,所有子VIEw一行一行的布局            List<VIEw> lineVIEws = vIEws.get(i); //取出一行、            int lineHeight = heights.get(i); //取出这一行的高度            //遍历当前行的子VIEw            int size = lineVIEws.size();            for(int j = 0; j < size; j++){                //布局当前行的每一个VIEw                VIEw child = lineVIEws.get(j);                int left = currX;                int top = currY;                int right = left + child.getMeasureDWIDth();                int bottom = top + child.getMeasuredHeight();                child.layout(left, top, right, bottom);                currX += child.getMeasureDWIDth();            }            currY += lineHeight;            currX = 0;        }    }    @OverrIDe    protected LayoutParams generateLayoutParams(VIEwGroup.LayoutParams p) {        return new LayoutParams(p);    }    @OverrIDe    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new LayoutParams(getContext(), attrs);    }    @OverrIDe    protected LayoutParams generateDefaultLayoutParams() {        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);    }    @OverrIDe    protected boolean checkLayoutParams(VIEwGroup.LayoutParams p) {        return super.checkLayoutParams(p) && p instanceof LayoutParams;    }    public static class LayoutParams extends marginLayoutParams{        public int gravity = -1;        public LayoutParams(Context c, AttributeSet attrs){            super(c, attrs);            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout);            try{                gravity = a.getInt(R.styleable.FlowLayout_Layout_androID_layout_gravity, -1);            }finally {                a.recycle();            }        }        public LayoutParams(int wIDth, int height) {            super(wIDth, height);        }        public LayoutParams(VIEwGroup.LayoutParams source) {            super(source);        }        @OverrIDe        public String toString() {            return "LayoutParams{" +                    "gravity=" + gravity +                    ", bottommargin=" + bottommargin +                    ", leftmargin=" + leftmargin +                    ", rightmargin=" + rightmargin +                    ", topmargin=" + topmargin +                    ", height=" + height +                    ", wIDth=" + wIDth +                    "} ";        }    }}
运行效果

总结

以上是内存溢出为你收集整理的Android自定义View之实现流式布局全部内容,希望文章能够帮你解决Android自定义View之实现流式布局所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/999720.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存