流式布局

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;


public class FlowLayout extends ViewGroup {
public FlowLayout(Context context) {
this (context, null );
}

public FlowLayout(Context context, AttributeSet attrs) {
this (context, attrs, 0 );
}

public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super (context, attrs, defStyleAttr);
}

private List<List<View>> mLineViews = new ArrayList<List<View>>();
private List<Integer> mLineHeight = new ArrayList<Integer>();

/**
* 测量所有子 View 大小 , 确定 ViewGroup 的宽高
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {
super .onMeasure(widthMeasureSpec, heightMeasureSpec);

// 由于 onMeasure 会执行多次 , 避免重复的计算控件个数和高度 , 这里需要进行清空操作
mLineViews .clear();
mLineHeight .clear();

// 获取测量的模式和尺寸大小
int widthMode = MeasureSpec. getMode (widthMeasureSpec);
int widthSize = MeasureSpec. getSize (widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
int heightMode = MeasureSpec. getMode (heightMeasureSpec);
int heightSize = MeasureSpec. getSize (heightMeasureSpec) + getPaddingTop() + getPaddingBottom();


// 记录 ViewGroup 真实的测量宽高
int viewGroupWidth = 0 - getPaddingLeft() - getPaddingRight();
int viewGroupHeight = getPaddingTop() + getPaddingBottom();

if (widthMode == MeasureSpec. EXACTLY && heightMode == MeasureSpec. EXACTLY ) {
viewGroupWidth = widthSize;
viewGroupHeight = heightSize;
} else {
// 当前所占的宽高
int currentLineWidth = 0 ;
int currentLineHeight = 0 ;

// 用来存储每一行上的子 View
List<View> lineView = new ArrayList<View>();
int childViewsCount = getChildCount();
for ( int i = 0 ; i < childViewsCount; i++) {
View childView = getChildAt(i);
// 对子 View 进行测量
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams();
int childViewWidth = childView.getMeasuredWidth() + marginLayoutParams. leftMargin + marginLayoutParams. rightMargin ;
int childViewHeight = childView.getMeasuredHeight() + marginLayoutParams. topMargin + marginLayoutParams. bottomMargin ;

if (currentLineWidth + childViewWidth > widthSize) {
// 当前行宽 + View+ 左右外边距 >ViewGroup 的宽度 , 换行
viewGroupWidth = Math. max (currentLineWidth, widthSize);
viewGroupHeight += currentLineHeight;
// 添加行高
mLineHeight .add(currentLineHeight);
// 添加行对象
mLineViews .add(lineView);

//new 新的一行
lineView = new ArrayList<View>();
// 添加行对象里的子 View
lineView.add(childView);
currentLineWidth = childViewWidth;

} else {
// 当前行宽 + View+ 左右外边距 <=ViewGroup 的宽度 , 不换行
currentLineWidth += childViewWidth;
currentLineHeight = Math. max (currentLineHeight, childViewHeight);
// 添加行对象里的子 View
lineView.add(childView);
}


if (i == childViewsCount - 1 ) {
// 最后一个子 View 的时候
// 添加行对象
mLineViews .add(lineView);
viewGroupWidth = Math. max (childViewWidth, viewGroupWidth);
viewGroupHeight += childViewHeight;
// 添加行高
mLineHeight .add(currentLineHeight);

}


}

}
setMeasuredDimension(viewGroupWidth, viewGroupHeight);
}
/**
* 设置 ViewGroup 里子 View 的具体位置
*
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout( boolean changed, int l, int t, int r, int b) {

int left = getPaddingLeft();
int top = getPaddingTop();
// 一共有几行
int lines = mLineViews .size();
for ( int i = 0 ; i < lines; i++) {
// 每行行高
int lineHeight = mLineHeight .get(i);
// 行内有几个子 View
List<View> viewList = mLineViews .get(i);
int views = viewList.size();

for ( int j = 0 ; j < views; j++) {
View view = viewList.get(j);
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams();
int vl = left + marginLayoutParams. leftMargin ;
int vt = top + marginLayoutParams. topMargin ;
int vr = vl + view.getMeasuredWidth();
int vb = vt + view.getMeasuredHeight();
view.layout(vl, vt, vr, vb);
left += view.getMeasuredWidth() + marginLayoutParams. leftMargin + marginLayoutParams. rightMargin ;
}
left = getPaddingLeft();
top += lineHeight;
}
}

/**
* 指定 ViewGroup LayoutParams
*
* @param attrs
* @return
*/
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}

}




XML代码


<? xml version= "1.0" encoding= "utf-8" ?>
< RelativeLayout 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" >

< EditText
android :id= "@+id/main_edit"
android :layout_width= "294dp"
android :layout_height= "48dp"
android :layout_alignParentStart= "true"
android :background= "@drawable/shape_bg"
android :ems= "10" />

< Button
android :id= "@+id/main_btn"
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_alignParentEnd= "true"
android :layout_alignParentTop= "true"
android :background= "@drawable/shape_bg"
android :text= " 搜索 " />

< com.example.weekdome.FlowLayout
android :id= "@+id/flow"
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_alignParentStart= "true"
android :layout_alignParentTop= "true"
android :layout_marginTop= "57dp" >

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 欧美影视 "
android :textColor= "@color/colorAccent" />

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 婚姻育儿 "
android :textColor= "@color/colorAccent" />

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 散文 "
android :textColor= "@color/colorAccent" />


< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 程序员 "
android :textColor= "@color/colorAccent" />

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 大学生生活 "
android :textColor= "@color/colorAccent" />

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 运营互助帮 "
android :textColor= "@color/colorAccent" />

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 设计 "
android :textColor= "@color/colorAccent" />

< TextView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :layout_margin= "8dp"
android :padding= "5dp"
android :text= " 读书 "
android :textColor= "@color/colorAccent" />
</ com.example.weekdome.FlowLayout >

< ListView
android :id= "@+id/history_list"
android :layout_width= "match_parent"
android :layout_height= "356dp"
android :layout_alignParentBottom= "true"
android :layout_alignParentStart= "true" />

</ RelativeLayout >
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值