安卓流式布局,经常用在 历史搜索框、人物标签 等安卓功能中, 对于没有经验的同学来说,要自己写流式布局确实是一个难点,或者写出来的自定义布局的运行效率也不高,这里是我自己整理出的一个非常好的例子, 拿出来跟大家交流学习。
1、 FlowViewGroup 类的java代码如下
package com.snippet.worklearn;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class FlowViewGroup extends ViewGroup {
private final static String TAG = "MyViewGroup2";
private final static int VIEW_MARGIN = 0;
public FlowViewGroup(Context context) {
super(context);
}
public FlowViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.d(TAG, "widthMeasureSpec = " + widthMeasureSpec
+ " heightMeasureSpec" + heightMeasureSpec);
// for (int index = 0; index < getChildCount(); index++) {
// final View child = getChildAt(index);
// // measure
// child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
// }
int measureWidth = measureWidth(widthMeasureSpec);
int measureHeight = measureHeight(heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(measureWidth, measureHeight);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
final int count = getChildCount();
int row = 0;
int left = arg1;
int top = arg2;
int right = arg3;
int bottom = arg4;
for (int i = 0; i < count; i++) {
final View child = this.getChildAt(i);
String text = ((TextView)child).getText().toString();
Log.e(TAG, text+" onLayout = " + arg0 + " left = " + arg1 + " top = " + arg2 + " right = " + arg3 + " botom = " + arg4);
int width = child.getMeasuredWidth();
int height = child.getMeasuredHeight();
Log.e("----1-----", "width="+width+" , height="+height + " , measuredWidth="+ child.getMeasuredWidth() + " , paddingLeft="+child.getPaddingLeft()
+ " , paddingRight=" + child.getPaddingRight() );
Log.e("----22--计算之前---", "left="+left+ " , right="+ right +" , top="+top );
left += width + VIEW_MARGIN;
top = row * (height + VIEW_MARGIN) + VIEW_MARGIN + height + arg2;
Log.e("----33--计算之后---", "left="+left+ " , right="+ right +" , top="+top );
if (left > right) {
left = width + VIEW_MARGIN + arg1;
row++;
top = row * (height + VIEW_MARGIN) + VIEW_MARGIN + height + arg2;
}
Log.e("----4444-----", "left="+(left - width)+" , top="+ (top - height) + " , right="+ left + " , bottom="+top );
child.layout(left - width-arg1, top - height, left-arg1, top);
}
}
private int measureWidth(int pWidthMeasureSpec) {
int result = 0;
int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);// 得到模式
int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);// 得到尺寸
switch (widthMode) {
/**
* mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,
* MeasureSpec.AT_MOST。
*
*
* MeasureSpec.EXACTLY是精确尺寸,
* 当我们将控件的layout_width或layout_height指定为具体数值时如andorid
* :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
*
*
* MeasureSpec.AT_MOST是最大尺寸,
* 当控件的layout_width或layout_height指定为WRAP_CONTENT时
* ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可
* 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
*
*
* MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,
* 通过measure方法传入的模式。
*/
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = widthSize;
break;
}
return result;
}
private int measureHeight(int pHeightMeasureSpec) {
int result = 0;
int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);
switch (heightMode) {
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = heightSize;
break;
}
return result;
}
}
2、 xml文件中 使用方法如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp" >
<com.snippet.worklearn.FlowViewGroup
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
android:background="#f0f" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center_vertical"
android:paddingLeft="20dp"
android:paddingRight="10dp"
android:text="两字" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="三个字" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="这是四字" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="五字超出没" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="梅凯三四五六七八" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="一" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="六字应该换行" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="七字肯定换行了" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="八字什么样子结果" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="一" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/aaa"
android:gravity="center"
android:text="呵呵" />
</com.snippet.worklearn.MyViewGroup2>
</LinearLayout>
3、运行效果图: