100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Android自定义View之实现流式布局

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

时间:2022-05-27 21:10:26

相关推荐

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

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="/apk/res/android"--><!--xmlns:app="/apk/res-auto"--><!--android:layout_width="match_parent"--><!--android:layout_height="wrap_content"--><!--xmlns:tools="/tools">--><LinearLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:orientation="vertical"android:layout_height="match_parent"><com.example.as.proj.myviewgroupdemo2.FlowLayout xmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:layout_width="wrap_content"android:layout_height="55dp"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="match_parent"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="90dp"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="85dp"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="45dp"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="75dp"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="60dp"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="85dp"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="100dp"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="85dp"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="85dp"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="65dp"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="100dp"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="75dp"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="80dp"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="300dp"android:text="生活不止眼前的苟且,还有诗和远方" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="发电房" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="小麻小儿郎呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Hello hi ..." /><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="你是谁呀" /><Buttonandroid:layout_width="wrap_content"android:layout_height="65dp"android:text="人在他在,塔亡人亡"android:layout_gravity="bottom"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="生活不止眼前的苟且,还有诗和远方1" /><Buttonandroid:layout_width="wrap_content"android:layout_height="250dp"android:text="发电房" /><Buttonandroid: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; //每一行的子Viewprivate 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<>();}@Overrideprotected 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_parentlineHeight = 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_parentremeasureChild(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); //每一行的子Viewint 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);}}}}@Overrideprotected 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); //取出这一行的高度//遍历当前行的子Viewint size = lineViews.size();for(int j = 0; j < size; j++){//布局当前行的每一个ViewView 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;}}@Overrideprotected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {return new LayoutParams(p);}@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new LayoutParams(getContext(), attrs);}@Overrideprotected LayoutParams generateDefaultLayoutParams() {return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);}@Overrideprotected 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);}@Overridepublic String toString() {return "LayoutParams{" +"gravity=" + gravity +", bottomMargin=" + bottomMargin +", leftMargin=" + leftMargin +", rightMargin=" + rightMargin +", topMargin=" + topMargin +", height=" + height +", width=" + width +"} ";}}}

运行效果

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。