package com.rongke.mifan.jiagang.view.flowLayout;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.rongke.mifan.jiagang.R;
import com.zyf.fwms.commonlibrary.utils.AutoUtils;
import com.zyf.fwms.commonlibrary.utils.CommonUtils;
import java.util.ArrayList;
import java.util.List;
public class FlowLayout extends ViewGroup {
private List valueList=new ArrayList<>();
private OnFlowClickLisener lisener;
public static final int DEFAULT_SPACING = 20;
/**
* 横向间隔
*/
private int mHorizontalSpacing = DEFAULT_SPACING;
/**
* 纵向间隔
*/
private int mVerticalSpacing = DEFAULT_SPACING;
/**
* 是否需要布局,只用于第一次
*/
boolean mNeedLayout = true;
/**
* 当前行已用的宽度,由子View宽度加上横向间隔
*/
private int mUsedWidth = 0;
/**
* 代表每一行的集合
*/
private final List mLines = new ArrayList();
private Line mLine = null;
/**
* 最大的行数
*/
private int mMaxLinesCount = Integer.MAX_VALUE;
Handler handler = new Handler();
private Context context;
private boolean isMore;
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
/**
* 初始化
* @param context
* @param attrs
*/
private void initView(Context context, AttributeSet attrs) {
this.context=context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
mHorizontalSpacing = a.getInt(R.styleable.FlowLayout_horizontal_spacing, DEFAULT_SPACING);
mVerticalSpacing = a.getInt(R.styleable.FlowLayout_vertical_spacing, DEFAULT_SPACING);
}
private TextView getDefualtTextView(){
TextView textView= (TextView) View.inflate(context,R.layout.flow_text_view,null);
textView.setWidth(CommonUtils.dip2px(context,71));
textView.setHeight(CommonUtils.dip2px(context,25));
textView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TextView textView= (TextView) v;
int position = (int) textView.getTag();
if(textView.isSelected()){
textView.setSelected(false);
if(valueList.contains(textView.getText().toString())){
valueList.remove(textView.getText().toString());
}
}else {
if(!isMore){
resetView();
}
textView.setSelected(true);
if(!valueList.contains(textView.getText().toString())){
valueList.add(textView.getText().toString());
}
}
}
});
AutoUtils.autoTextSize(textView);
return textView;
}
private void resetView(){
valueList.clear();
for(int i=0;ifalse);
}
}
/**
*
* @param list 显示的列表
* @param isMore 是否多选
* @param lisener 回调
*/
public void setView(List list,boolean isMore,OnFlowClickLisener lisener){
valueList.clear();
this.lisener=lisener;
this.isMore=isMore;
addViewList(list);
}
public interface OnFlowClickLisener{
void onClick(List valueList);
}
private void addViewList(List list) {
removeAllViews();
for(int i=0;i/**
* 水平宽度
*
* @param spacing
*/
public void setHorizontalSpacing(int spacing) {
if (mHorizontalSpacing != spacing) {
mHorizontalSpacing = spacing;
requestLayoutInner();
}
}
/**
* 上下宽度
*
* @param spacing
*/
public void setVerticalSpacing(int spacing) {
if (mVerticalSpacing != spacing) {
mVerticalSpacing = spacing;
requestLayoutInner();
}
}
/**
* 最大行数
*
* @param count
*/
public void setMaxLines(int count) {
if (mMaxLinesCount != count) {
mMaxLinesCount = count;
requestLayoutInner();
}
}
private void requestLayoutInner() {
handler.post(new Runnable() {
@Override
public void run() {
requestLayout();
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingRight() - getPaddingLeft();
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
restoreLine();// 还原数据,以便重新记录
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(sizeWidth, modeWidth == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeWidth);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(sizeHeight, modeHeight == MeasureSpec.EXACTLY ? MeasureSpec.AT_MOST : modeHeight);
// 测量child
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
if (mLine == null) {
mLine = new Line();
}
int childWidth = child.getMeasuredWidth();
mUsedWidth += childWidth;// 增加使用的宽度
if (mUsedWidth <= sizeWidth) {// 使用宽度小于总宽度,该child属于这一行。
mLine.addView(child);// 添加child
mUsedWidth += mHorizontalSpacing;// 加上间隔
if (mUsedWidth >= sizeWidth) {// 加上间隔后如果大于等于总宽度,需要换行
if (!newLine()) {
break;
}
}
} else {// 使用宽度大于总宽度。需要换行
if (mLine.getViewCount() == 0) {// 如果这行一个child都没有,即使占用长度超过了总长度,也要加上去,保证每行都有至少有一个child
mLine.addView(child);// 添加child
if (!newLine()) {// 换行
break;
}
} else {// 如果该行有数据了,就直接换行
if (!newLine()) {// 换行
break;
}
// 在新的一行,不管是否超过长度,先加上去,因为这一行一个child都没有,所以必须满足每行至少有一个child
mLine.addView(child);
mUsedWidth += childWidth + mHorizontalSpacing;
}
}
}
if (mLine != null && mLine.getViewCount() > 0 && !mLines.contains(mLine)) {
// 由于前面采用判断长度是否超过最大宽度来决定是否换行,则最后一行可能因为还没达到最大宽度,所以需要验证后加入集合中
mLines.add(mLine);
}
int totalWidth = MeasureSpec.getSize(widthMeasureSpec);
int totalHeight = 0;
final int linesCount = mLines.size();
for (int i = 0; i < linesCount; i++) {// 加上所有行的高度
totalHeight += mLines.get(i).mHeight;
}
totalHeight += mVerticalSpacing * (linesCount - 1);// 加上所有间隔的高度
totalHeight += getPaddingTop() + getPaddingBottom();// 加上padding
// 设置布局的宽高,宽度直接采用父view传递过来的最大宽度,而不用考虑子view是否填满宽度,因为该布局的特性就是填满一行后,再换行
// 高度根据设置的模式来决定采用所有子View的高度之和还是采用父view传递过来的高度
setMeasuredDimension(totalWidth, resolveSize(totalHeight, heightMeasureSpec));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (!mNeedLayout || changed) {//没有发生改变就不重新布局
mNeedLayout = false;
int left = getPaddingLeft();//获取最初的左上点
int top = getPaddingTop();
final int linesCount = mLines.size();
for (int i = 0; i < linesCount; i++) {
final Line oneLine = mLines.get(i);
oneLine.layoutView(left, top);//布局每一行
top += oneLine.mHeight + mVerticalSpacing;//为下一行的top赋值
}
}
}
/**
* 还原所有数据
*/
private void restoreLine() {
mLines.clear();
mLine = new Line();
mUsedWidth = 0;
}
/**
* 新增加一行
*/
private boolean newLine() {
mLines.add(mLine);
if (mLines.size() < mMaxLinesCount) {
mLine = new Line();
mUsedWidth = 0;
return true;
}
return false;
}
// ==========================================================================
// Inner/Nested Classes
// ==========================================================================
/**
* 代表着一行,封装了一行所占高度,该行子View的集合,以及所有View的宽度总和
*/
class Line {
int mWidth = 0;// 该行中所有的子View累加的宽度
int mHeight = 0;// 该行中所有的子View中高度的那个子View的高度
List views = new ArrayList();
public void addView(View view) {// 往该行中添加一个
views.add(view);
mWidth += view.getMeasuredWidth();
int childHeight = view.getMeasuredHeight();
mHeight = mHeight < childHeight ? childHeight : mHeight;//高度等于一行中最高的View
}
public int getViewCount() {
return views.size();
}
public void layoutView(int l, int t) {// 布局
int left = l;
int top = t;
int cnull