把子控件从左到右摆放,如果一行放不下,自动放到下一行自定义布局流程
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之实现流式布局所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)