Android可以换行的布局
本文讨论的是下图的这种数据展示方式
通过本文可以学到的内容
===View绘制的工作流程measure和Layout,即测量和布局;
===动态创建和添加子View,以及设置点击事件的一种思路
1、主要使用的是一个继承自ViewGroup的自定义类NewLineLayout
代码如下:
/** * 可以换行的布局 */ import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import com.orhanobut.logger.Logger; public class NewLineLayout extends ViewGroup { private int mScreenWidth;//屏幕宽度 private int horizontalSpace, verticalSpace;//子View间距 public NewLineLayout(Context context) { this(context, null); } public NewLineLayout(Context context, AttributeSet attrs) { super(context, attrs); mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; } @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); //摆放子view View child; //子view摆放的起始位置 int left = getPaddingLeft(); //存储一行view最大的高度,用于子view进行换行时高度的计算 int maxHeightInLine = 0; //存储所有行的高度相加,用于确定此容器的高度 int allHeight = 0; //遍历子view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { child = getChildAt(i); //测量子View宽高 measureChild(child, widthMeasureSpec, heightMeasureSpec); //两两对比,取得一行中最大的高度 int childHeight = child.getMeasuredHeight() + child.getPaddingTop() + child.getPaddingBottom(); if (childHeight > maxHeightInLine) { maxHeightInLine = childHeight; } left += child.getMeasuredWidth() + horizontalSpace + child.getPaddingLeft() + child.getPaddingRight(); //这一行所有子view相加的宽度大于容器的宽度,需要换行 if (left > widthSize - getPaddingRight()) { //换行的首个子view,起始left为容器的paddingLeft left = getPaddingLeft(); //累积行的总高度 allHeight += maxHeightInLine + verticalSpace; //重置最大高度 maxHeightInLine = 0; } else { allHeight += maxHeightInLine; } } if (widthMode != MeasureSpec.EXACTLY) { widthSize = mScreenWidth;//如果没有指定宽,则默认为屏幕宽 } if (heightMode != MeasureSpec.EXACTLY) {//如果没有指定高度 heightSize = allHeight + getPaddingBottom() + getPaddingTop(); } setMeasuredDimension(widthSize, heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (changed) { //摆放子view View child; //子view摆放的起始位置 int left = getPaddingLeft(); int top = getPaddingTop(); //存储一行view最大的高度,用于子view进行换行时高度的计算 int maxHeightInLine = 0; for (int i = 0, len = getChildCount(); i < len; i++) { child = getChildAt(i); //从第二个子view开始算起 //第一个子view默认从头开始摆放 if (i > 0) { //两两对比,取得一行中最大的高度 if (getChildAt(i - 1).getMeasuredHeight() > maxHeightInLine) { maxHeightInLine = getChildAt(i - 1).getMeasuredHeight(); } //当前子view的起始left为 上一个子view的宽度+水平间距 left += getChildAt(i - 1).getMeasuredWidth() + horizontalSpace; //这一行所有子view相加的宽度大于容器的宽度,需要换行 if (left + child.getMeasuredWidth() > getWidth() - getPaddingRight()) { //换行的首个子view,起始left为容器的paddingLeft left = getPaddingLeft(); //top的位置为上一行中拥有最大高度的某个View的高度+垂直间距 top += maxHeightInLine + verticalSpace; //将上一行View的最大高度置0 maxHeightInLine = 0; } } //摆放子view child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight()); } } } /** * 设置子view间的水平间距 * * @param horizontalSpace */ public void setHorizontalSpace(int horizontalSpace) { this.horizontalSpace = horizontalSpace; } /** * 设置子view间的垂直间距 * * @param verticalSpace */ public void setVerticalSpace(int verticalSpace) { this.verticalSpace = verticalSpace; } }
注释比较清楚,耐心点绝对能理解
2、动态创建TextView的方法
/** * 创建自定义View * * @param text 文本内容 */ private TextView newCustomTextView(String text) { TextView textView = new TextView(activity); textView.setText(text); //指定文字大小 textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, activity.getResources().getDimension(R.dimen.font_text)); //设置最小宽高 textView.setMinHeight((int) activity.getResources().getDimension(R.dimen.text_height)); textView.setMinWidth((int) activity.getResources().getDimension(R.dimen.text_width)); //设置内边距 int padding = (int) activity.getResources().getDimension(R.dimen.space_tiny); textView.setPadding(padding, 0, padding, 0); textView.setGravity(Gravity.CENTER); return textView; }
3、添加子View,利用tag属性关联View点击事件
private String lineString = "_";//自定义分割字符 private void initView() { final TextView[] textViewArray = new TextView[dataList.length]; View.OnClickListener onClickListener = new View.OnClickListener() { @Override public void onClick(View view) { String tag = (String) view.getTag(); if (!StringUtil.isEmpty(tag)) { int lineIndex = tag.indexOf(lineString); int index = StringUtil.toInt(tag.substring(0, lineIndex), 0); //处理按钮组单选的情况 changeButtonState(textViewArray, index); ToastUtil.showShortToast(activity, dataList[index]); } } }; for (int i = 0; i < dataList.length; i++) { textViewArray[i] = newCustomTextView(dataList[i]); //组合tag处理单击事件 String tag = i + lineString + dataList[i]; textViewArray[i].setTag(tag); textViewArray[i].setOnClickListener(onClickListener); //添加自定义View layContent.addView(textViewArray[i]); } }
4、按钮组的单选实现方法
/** * 单选按钮组 * * @param index 根据序号改变按钮组的状态 */ public void changeButtonState(TextView[] textView, int index) { int size = textView.length; for (int i = 0; i < size; i++) { textView[i].setBackgroundResource(text_normal); textView[i].setTextColor(txt_normal); } textView[index].setBackgroundResource(text_select); textView[index].setTextColor(txt_select); }
===代码地址===
Android可以换行的布局的更多相关文章
- Android经常使用的布局类整理(一)
Android经常使用的布局类整理 近期又回头做了一下android的项目,发觉越来越不从心,非常多东西都忘了,简单的页面布局也非常多写不出来,首先还是先整理一下一些会混淆的概念先 layout_wi ...
- Android UI组件:布局管理器
为了更好的管理Android应用的用户界面中的组件,Android提供了布局管理器.通过使用布局管理器,Android应用的图形用户界面具有良好的平台无关性.通常,推荐使用布局管理器来管理组件的分布. ...
- Android中的LinearLayout布局
LinearLayout : 线性布局 在一般情况下,当有很多控件需要在一个界面列出来时,我们就可以使用线性布局(LinearLayout)了, 线性布局是按照垂直方向(vertical)或水平方向 ...
- Android开发-之五大布局
在html中大家都知道布局是什么意思了,简单来说就是将页面划分模块,比如html中的div.table等.那么Android中也是这样的.Android五大布局让界面更加美化,开发起来也更加方便.当然 ...
- 简单研究Android View绘制三 布局过程
2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...
- Android性能优化之布局优化
最新最准确内容建议直接访问原文:Android性能优化之布局优化 本文为Android性能优化的第二篇——布局优化,主要介绍使用抽象布局标签(include, viewstub, merge).去除不 ...
- Android中的五大布局
Android中的五大布局 1.了解布局 一个丰富的界面总是要由很多个控件组成的,那我们如何才能让各个控件都有条不紊地 摆放在界面上,而不是乱糟糟的呢?这就需要借助布局来实现了.布局是一种可用于放置很 ...
- 关于android LinearLayout的比例布局(转载)
关于android LinearLayout的比例布局,主要有以下三个属性需要设置: 1,android:layout_width,android:layout_height,android:layo ...
- 【转】Android性能优化之布局优化篇
转自:http://blog.csdn.net/feiduclear_up/article/details/46670433 Android性能优化之布局优化篇 分类: andorid 开发2015 ...
随机推荐
- 过程 : 概念 : 结构 jobbox jobPost
概念是employer创建jobPost时,可以publish或unpublish. sort expired后,会通过server tast 去更新成history.所有的publish和unpub ...
- nodeJS中读写文件方法的区别
导言:nodejs中所有与文件相关的操作都在fs模块中,而读写操作又是我们会经常用到的操作,nodejs的fs模块针对读操作为我们提供了readFile,read, createReadStream三 ...
- Ubuntu16.04下搭建LAMP环境
前期准备sudo apt-get update # 获取最新资源包sudo apt-get upgrade # 本机软件全部更新sudo apt-get d ...
- [vijosP1303]导弹拦截(最长上升子序列转LCS)
描述 某国为了防御敌国的导弹袭击,研发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭 ...
- Spring 3.0 Aop 入门
关于Aop的原理,动态代理,反射,之类的底层java技术网上搜一堆一堆的..我就不多说了,主要说在spring上使用aop的方法. 首先不得不说一下的就是,spring aop的支持需要外部依赖包: ...
- AJAX遮罩实例
function transferip() { var site_list=$("textarea[name='Oldsite']").val(); var ip_list=$(& ...
- Pydev--unresolved import:解决办法
1.右键点击项目,选择Properties-->Pydev-Interpreter/Grammar 2.点击"Click here to configure an interprete ...
- sqlplus入门使用
1.如果在PL/SQL 等工具里打开的话,直接修改下面的代码中[斜体加粗部分]执行 2.确保路径存在,比如[D:\oracle\oradata\Oracle9i\]也就是你要保存文件的路径存在 /*分 ...
- python 机器学习 K-近邻算法
本人想边写文章,边学习,用的是 网上最火的<机器学习实战>machine learning in action 来做一次实践. 希望在过程中理顺思路之余,也有分享自己的一些理解,学习.加油 ...
- Omi框架学习之旅 - Hello World 及原理说明
学什么东西都从hello world开始, 我也不知道为啥. 恩,先上demo代码, 然后提出问题, 之后解答问题, 最后源码说明. hello world - demo: class Hello e ...