代码改变世界

热门话题自动换行自定义控件

2015-08-24 15:44  一切尽在掌握  阅读(272)  评论(0编辑  收藏  举报

实现根据textview的宽度实现自动换行的自定义控件:

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

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

public class CusGroup extends ViewGroup {

	public CusGroup(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected ViewGroup.LayoutParams generateLayoutParams(
			ViewGroup.LayoutParams p) {
		return new MarginLayoutParams(p);
	}

	@Override
	public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
		return new MarginLayoutParams(getContext(), attrs);
	}

	@Override
	protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
		return new MarginLayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT);
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);

		int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
		int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
		int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
		int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

		// 记录宽和高
		int width = 0;
		int height = 0;

		// 每行宽
		int lineWidth = 0;
		// 每行高
		int lineHeight = 0;

		int cCount = getChildCount();

		for (int i = 0; i < cCount; i++) {
			View child = getChildAt(i);
			// 子VIew的宽和高
			measureChild(child, widthMeasureSpec, heightMeasureSpec);

			MarginLayoutParams lp = (MarginLayoutParams) child
					.getLayoutParams();
			// 子View所占宽高
			int childWidth = child.getMeasuredWidth() + lp.leftMargin
					+ lp.rightMargin;
			int childHeight = child.getMeasuredHeight() + lp.topMargin
					+ lp.bottomMargin;

			// 比较换行
			if (lineWidth + childWidth > sizeWidth) {
				width = Math.max(lineWidth, childWidth);
				lineWidth = childWidth;
				// 新行
				height += lineHeight;
				// 下一行的高度
				lineHeight = childHeight;
			} else {
				lineWidth += childWidth;
				lineHeight = Math.max(lineHeight, childHeight);
			}
			// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较
			if (i == cCount - 1) {
				width = Math.max(width, lineWidth);
				height += lineHeight;
			}

		}
		setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth
				: width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight
				: height);

	}

	// 存储所有的View,按行记录
	private List<List<View>> mAllViews = new ArrayList<List<View>>();

	// 记录每一行的最大高度
	private List<Integer> mLineHeight = new ArrayList<Integer>();

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		mAllViews.clear();
		mLineHeight.clear();

		int width = getWidth();

		int lineWidth = 0;
		int lineHeight = 0;
		// 存储每一行所有的childView
		List<View> lineViews = new ArrayList<View>();
		int cCount = getChildCount();

		for (int i = 0; i < cCount; i++) {
			View child = getChildAt(i);
			MarginLayoutParams lp = (MarginLayoutParams) child
					.getLayoutParams();
			int childWidth = child.getMeasuredWidth();
			int childHeight = child.getMeasuredHeight();

			// 如果已经需要换行
			if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width) {
				// 记录这一行所有的View以及最大高度
				mLineHeight.add(lineHeight);
				// 将当前行的childView保存,然后new ArrayList保存下一行的childView
				mAllViews.add(lineViews);
				lineWidth = 0;// 重置行宽
				lineViews = new ArrayList<View>();
			}
			/**
			 * 如果不需要换行,则累加
			 */
			lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
			lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
					+ lp.bottomMargin);
			lineViews.add(child);
		}
		// 记录最后一行
		mLineHeight.add(lineHeight);
		mAllViews.add(lineViews);

		int left = 0;
		int top = 0;
		// 总行数
		int lineNums = mAllViews.size();
		for (int i = 0; i < lineNums; i++) {
			// 每一行的所有的views
			lineViews = mAllViews.get(i);
			// 当前行的最大高度
			lineHeight = mLineHeight.get(i);

			for (int j = 0; j < lineViews.size(); j++) {
				View child = lineViews.get(j);
				if (child.getVisibility() == View.GONE) {
					continue;
				}
				MarginLayoutParams lp = (MarginLayoutParams) child
						.getLayoutParams();

				int lc = left + lp.leftMargin;
				int tc = top + lp.topMargin;
				int rc = lc + child.getMeasuredWidth();
				int bc = tc + child.getMeasuredHeight();

				child.layout(lc, tc, rc, bc);

				left += child.getMeasuredWidth() + lp.rightMargin
						+ lp.leftMargin;
			}
			left = 0;
			top += lineHeight;
		}

	}
}

 使用:

public class MainActivity extends Activity implements OnItemClickListener,
		 OnClickListener {

	private CusGroup cg;
	private List<String> allTags;
	private Context context;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		context = this;
		initView();
	}

	public void initView() {
		//从服务器动态获取
		allTags = new ArrayList<String>();
		allTags.add("暴走大事件hahahahahhahahahhahahahha");
		allTags.add("暴走好声音");
		allTags.add("王尼玛");
		allTags.add("末日hehehehhehehehehhehehehheheheh");
		allTags.add("越狱");

		//自定义的view
		cg = (CusGroup) findViewById(R.id.cg);
		for(int i=0;i<allTags.size();i++){
		//显示的内容
		String newtag = allTags.get(i);
		// 创建TextView
		final TextView newTagTv = creatTagTextView(newtag, false);
		newTagTv.setTag(newtag);
		//向顶部自定义view加的末尾子view
			cg.addView(newTagTv,i);
		
		//给加的子View设置监听
		newTagTv.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
//				changTagStyle((TextView)v, true);
				//直接给textview设置背景选择器
				Toast.makeText(context, newTagTv.getText(), 0).show();
			}
		});
		}
	}

	/**
	 * 在CusGroup中创建新的TextView
	 */
	private TextView creatTagTextView(String str, boolean flag) {
		TextView newTagTv = new TextView(context);
		newTagTv.setText(str);
		newTagTv.setSingleLine(true);
		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
				LinearLayout.LayoutParams.WRAP_CONTENT,
				LinearLayout.LayoutParams.WRAP_CONTENT);
		lp.setMargins(8, 8, 8, 8);
		newTagTv.setPadding(10, 2, 10, 2);
		newTagTv.setLayoutParams(lp);
		newTagTv.setGravity(Gravity.CENTER);
		changTagStyle(newTagTv, flag);
		return newTagTv;
	}

	/**
	 * 改变标签背景颜色
	 * 
	 * @param view
	 * @param flag
	 *            true:选中
	 */
	private void changTagStyle(TextView view, boolean flag) {
		if (flag) {
			//设置背景选择器即可
			view.setBackgroundResource(R.drawable.kno_my_tag);
			view.setTextColor(Color.GREEN);
		} else {
			view.setBackgroundResource(R.drawable.kno_select_tag);
			view.setTextColor(Color.BLACK);
		}
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
		// TODO Auto-generated method stub
		
	}

}

 支持增加的删除