GithubHelp home page GithubHelp logo

ayasealter / linebreaklayout Goto Github PK

View Code? Open in Web Editor NEW

This project forked from openxu/linebreaklayout

1.0 2.0 0.0 649 KB

自定义控件——自动换行的标签容器LineBreakLayout

Home Page: http://blog.csdn.net/xmxkf/article/details/52336144

License: MIT License

Java 100.00%

linebreaklayout's Introduction

LineBreakLayout--自动换行的标签容器

讲解博客 : http://blog.csdn.net/xmxkf/article/details/52336144

效果图:

LineBreakLayout.gif

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

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


public class LineBreakLayout extends ViewGroup {
	private final static String TAG = "LineBreakLayout";
	/**
	 * 所有标签
	 */
	private List<String> lables;
	/**
	 * 选中标签
	 */
	private List<String> lableSelected = new ArrayList<>();

	//自定义属性
	private int LEFT_RIGHT_SPACE; //dip
	private int ROW_SPACE;

	public LineBreakLayout(Context context) {
		this(context, null);
	}
	public LineBreakLayout(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}
	public LineBreakLayout(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LineBreakLayout);
		LEFT_RIGHT_SPACE = ta.getDimensionPixelSize(R.styleable.LineBreakLayout_leftAndRightSpace, 10);
		ROW_SPACE = ta.getDimensionPixelSize(R.styleable.LineBreakLayout_rowSpace, 10);
		ta.recycle(); //回收
		// ROW_SPACE=20   LEFT_RIGHT_SPACE=40
		Log.v(TAG, "ROW_SPACE="+ROW_SPACE+"   LEFT_RIGHT_SPACE="+LEFT_RIGHT_SPACE);
	}

	/**
	 * 添加标签
	 * @param lables 标签集合
	 * @param add 是否追加
     */
	public void setLables(List<String> lables, boolean add){
		if(this.lables == null){
			this.lables = new ArrayList<>();
		}
		if(add){
			this.lables.addAll(lables);
		}else{
			this.lables.clear();
			this.lables = lables;
		}
		if(lables!=null && lables.size()>0){
			LayoutInflater inflater = LayoutInflater.from(getContext());
			for (final String lable : lables) {
				//获取标签布局
				final TextView tv = (TextView) inflater.inflate(R.layout.item_lable, null);
				tv.setText(lable);
				//设置选中效果
				if (lableSelected.contains(lable)) {
					//选中
					tv.setSelected(true);
					tv.setTextColor(getResources().getColor(R.color.tv_blue));
				} else {
					//未选中
					tv.setSelected(false);
					tv.setTextColor(getResources().getColor(R.color.tv_gray));
				}
				//点击标签后,重置选中效果
				tv.setOnClickListener(new View.OnClickListener() {
					@Override
					public void onClick(View v) {
						tv.setSelected(tv.isSelected() ? false : true);
						if (tv.isSelected()) {
							tv.setTextColor(getResources().getColor(R.color.tv_blue));
							//将选中的标签加入到lableSelected中
							lableSelected.add(lable);
						} else {
							tv.setTextColor(getResources().getColor(R.color.tv_gray));
							lableSelected.remove(lable);
						}
					}
				});
				//将标签添加到容器中
				addView(tv);
			}
		}
	}

	/**
	 * 获取选中标签
     */
	public List<String> getSelectedLables(){
		return lableSelected;
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		//为所有的标签childView计算宽和高
		measureChildren(widthMeasureSpec, heightMeasureSpec);

		//获取高的模式
		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
		//建议的高度
		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
		//布局的宽度采用建议宽度(match_parent或者size),如果设置wrap_content也是match_parent的效果
		int width = MeasureSpec.getSize(widthMeasureSpec);

		int height ;
		if (heightMode == MeasureSpec.EXACTLY) {
			//如果高度模式为EXACTLY(match_perent或者size),则使用建议高度
			height = heightSize;
		} else {
			//其他情况下(AT_MOST、UNSPECIFIED)需要计算计算高度
			int childCount = getChildCount();
			if(childCount<=0){
				height = 0;   //没有标签时,高度为0
			}else{
				int row = 1;  // 标签行数
				int widthSpace = width;// 当前行右侧剩余的宽度
				for(int i = 0;i<childCount; i++){
					View view = getChildAt(i);
					//获取标签宽度
					int childW = view.getMeasuredWidth();
					Log.v(TAG , "标签宽度:"+childW +" 行数:"+row+"  剩余宽度:"+widthSpace);
					if(widthSpace >= childW ){
						//如果剩余的宽度大于此标签的宽度,那就将此标签放到本行
						widthSpace -= childW;
					}else{
						row ++;    //增加一行
						//如果剩余的宽度不能摆放此标签,那就将此标签放入一行
						widthSpace = width-childW;
					}
					//减去标签左右间距
					widthSpace -= LEFT_RIGHT_SPACE;
				}
				//由于每个标签的高度是相同的,所以直接获取第一个标签的高度即可
				int childH = getChildAt(0).getMeasuredHeight();
				//最终布局的高度=标签高度*行数+行距*(行数-1)
				height = (childH * row) + ROW_SPACE * (row-1);

				Log.v(TAG , "总高度:"+height +" 行数:"+row+"  标签高度:"+childH);
			}
		}

		//设置测量宽度和测量高度
		setMeasuredDimension(width, height);
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int row = 0;
		int right = 0;   // 标签相对于布局的右侧位置
		int botom;       // 标签相对于布局的底部位置
		for (int i = 0; i < getChildCount(); i++) {
			View childView = getChildAt(i);
			int childW = childView.getMeasuredWidth();
			int childH = childView.getMeasuredHeight();
			//右侧位置=本行已经占有的位置+当前标签的宽度
			right += childW;
			//底部位置=已经摆放的行数*(标签高度+行距)+当前标签高度
			botom = row * (childH + ROW_SPACE) + childH;
			// 如果右侧位置已经超出布局右边缘,跳到下一行
			// if it can't drawing on a same line , skip to next line
			if (right > (r - LEFT_RIGHT_SPACE)){
				row++;
				right = childW;
				botom = row * (childH + ROW_SPACE) + childH;
			}
			Log.d(TAG, "left = " + (right - childW) +" top = " + (botom - childH)+
					" right = " + right + " botom = " + botom);
			childView.layout(right - childW, botom - childH,right,botom);

			right += LEFT_RIGHT_SPACE;
		}
	}

}

linebreaklayout's People

Contributors

openxu avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.