android 实现自动换行的流布局
来源:互联网 发布:淘宝全民疯抢什么意思 编辑:程序博客网 时间:2024/04/30 05:45
今天为大家带来一个自定义的ViewGroup自动换行的流布局。原理非常的简单。就是在自定义的ViewGroup的onMeasure中计算每个子View的位置,再在onLayout中画出子View。别的不多说,直接上代码。
package com.ljh.flowviewgroup;import android.content.Context;import android.os.Build;import android.util.ArrayMap;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import java.util.HashMap;import java.util.Map;import java.util.Objects;/** * Created by liujinhua on 15/10/8. */public class FlowViewGroup extends ViewGroup { public FlowViewGroup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public FlowViewGroup(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowViewGroup(Context context) { this(context, null); } @Override protected LayoutParams generateDefaultLayoutParams() { return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } private Map<View, ChildViewPosition> map; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (map == null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { map = new ArrayMap<View, ChildViewPosition>(); } else { map = new HashMap<View, ChildViewPosition>(); } } else { map.clear(); } //计算所有ziView的大小 measureChildren(widthMeasureSpec, heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHight = MeasureSpec.getSize(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int hightMode = MeasureSpec.getMode(heightMeasureSpec); int lineWidth = 0; int lineHight = 0; int width = 0; int hight = 0; int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); MarginLayoutParams lp; if (childView.getLayoutParams() instanceof MarginLayoutParams) { lp = (MarginLayoutParams) childView.getLayoutParams(); } else { lp = new MarginLayoutParams(childView.getLayoutParams()); } int childWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childHight = childView.getMeasuredHeight() + lp.bottomMargin + lp.topMargin; //判断是非需要换行 if (lineWidth + childWidth > sizeWidth) { //需要换行 //计算ViewGroup需要的宽高 width = Math.max(width, lineWidth); hight += lineHight; //换行重置当前行高度与宽度 lineHight = childHight; lineWidth = childWidth; map.put(childView, new ChildViewPosition(0 + lp.leftMargin, hight + lp.topMargin, childWidth - lp.rightMargin, hight + childHight - lp.bottomMargin)); } else { //不需要换行 map.put(childView, new ChildViewPosition(lineWidth + lp.leftMargin, hight + lp.topMargin, lineWidth + childWidth - lp.rightMargin, hight + childHight - lp.bottomMargin)); //叠加当前行的宽度 lineWidth += childWidth; //计算当前行最大高度 lineHight = Math.max(lineHight, childHight); } //加上最后一行的宽高的计算出ViewGroup需要的宽高 if (i == childCount - 1) { width = Math.max(width, lineWidth); hight += lineHight; } } setMeasuredDimension( widthMode == MeasureSpec.EXACTLY ? sizeWidth : width, hightMode == MeasureSpec.EXACTLY ? sizeHight : hight ); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { for (View key : map.keySet()) { ChildViewPosition position = map.get(key); key.layout(position.left, position.top, position.right, position.bottom); } } private class ChildViewPosition { public ChildViewPosition(int left, int top, int right, int bottom) { this.left = left; this.right = right; this.top = top; this.bottom = bottom; } int left; int right; int top; int bottom; }}
package com.ljh.flowviewgroup;import android.graphics.Color;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends AppCompatActivity { FlowViewGroup flowViewGroup; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); flowViewGroup = (FlowViewGroup) findViewById(R.id.flowViewGroup); for (int i = 0; i < 20; i++) { TextView text = new TextView(this); text.setText(" texttext" + i + " "); text.setBackgroundResource(R.drawable.round); text.setPadding(10, 10, 10, 10); flowViewGroup.addView(text); ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) text.getLayoutParams(); lp.bottomMargin = 10; lp.topMargin = 10; lp.rightMargin = 10; lp.leftMargin = 10; text.setLayoutParams(lp); } }}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <com.ljh.flowviewgroup.FlowViewGroup android:id="@+id/flowViewGroup" android:layout_width="wrap_content" android:layout_height="wrap_content"> </com.ljh.flowviewgroup.FlowViewGroup></RelativeLayout>
附上原代码 下载
0 0
- android 实现自动换行的流布局
- android 流布局(根据内容宽度自动换行的布局)
- JavaScript实现瀑布流布局以及页面的自动加载
- Android 中自动换行的标签实现
- 简单的流布局实现
- 瀑布流布局的实现
- Android RecyclerView实现瀑布流布局
- Android 自定义View实现文本流布局
- android recyclerview实现自动换行
- 瀑布流布局并自动加载实现代码
- 瀑布流布局的实现(一)
- 瀑布流布局的几种实现
- 底部PopupWindow+流布局的实现
- 瀑布流布局的原理及实现
- RecyclerView瀑布流布局的实现
- Android版的瀑布流布局
- Android中如何实现EditText的自动换行
- JXL自动换行的实现
- HDU 5536 (ACM 2015 长春) Chip Factory [Trie树]
- C++primer 17.2 bitset类型
- 用循环链表实现队列
- Linux下忘记mysql的root密码
- mysql 源码入门阅读调试笔记.
- android 实现自动换行的流布局
- Git/Framework静态库介绍:创建和使用
- SQL转Java代码小工具(改进)
- hdu 5536 trie树
- Hibernate4 HelloWorld
- 安全认证
- Mangos源码分析(8):服务器公共组件实现之消息队列
- 疯狂java讲义4.2--浮点数转换成人民币读法
- lsof 进程与文件