自定义View-自动换行的标签控件
android自定义换行标签:最近项目中需要实现一个功能:
网上有很多可以用的开源控件,我自己也学习写了一个自定义换行标签,让一个View继承ViewGroup,重写onmeasure()和onlayout()方法,核心代码如下
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //最后测量宽度和高度 int resultWidth = 0; int resultHeigh = 0; //临时测量宽度和高度 int linewidth = 0; int lineHeight = 0; int childCount = getChildCount(); //测量控件的宽高模式 在之前文章中有讲过这个用法,不懂的可以看下 int heightSize = MeasureSpec.getSize(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); //测量每一个子view的宽和高 measureChild(childView, widthMeasureSpec, heightMeasureSpec); //获取测量的高度 int childWidth = childView.getMeasuredWidth(); int childHeight = childView.getMeasuredHeight(); //因为子View可能设置margin,这里要加上margin的距离 MarginLayoutParams mlp = (MarginLayoutParams) childView.getLayoutParams(); //子控件真实宽度和高度 int realwidth = mlp.leftMargin + childWidth + mlp.rightMargin; int realHight = mlp.topMargin + childHeight + mlp.bottomMargin; //计算宽度 if (linewidth + realwidth > widthSize) { //换行 resultWidth = Math.max(linewidth, realwidth); resultHeigh = resultHeigh + realHight; //换行后高度和宽度重新计算 linewidth = realwidth; lineHeight = realHight; } else { linewidth = linewidth + realwidth; lineHeight = Math.max(lineHeight, realHight); } } //保存测量完成后的宽度和高度 setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : resultWidth, heightMode == MeasureSpec.EXACTLY ? heightSize : resultHeigh); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //子控件左边距离和上边距离 int childleft = 0; int childtop = 0; //为每个孩子布局 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); int measuredHeight = childView.getMeasuredHeight(); int measuredWidth = childView.getMeasuredWidth(); //因为子View可能设置margin,这里要加上margin的距离 MarginLayoutParams mlp = (MarginLayoutParams) childView.getLayoutParams(); if (childleft + mlp.leftMargin + mlp.rightMargin + measuredWidth > getWidth()) { //换行上边距离增加,左边距离为0 childtop = childtop + mlp.topMargin + mlp.bottomMargin + measuredHeight; childleft = 0; }
//计算子控件 int left = childleft + mlp.leftMargin; int top = childtop + mlp.topMargin; int right = childleft + mlp.leftMargin + mlp.rightMargin + measuredWidth; int bottom = childtop + mlp.topMargin + mlp.bottomMargin + measuredHeight;
//布局子控件 childView.layout(left, top, right, bottom); //不换行左边距离是前面子控件宽度之和 childleft = childleft + mlp.leftMargin + mlp.rightMargin + measuredWidth; } }
这样我们基本完成了该控件的绘制,我们通过addview加入子控件,例如:
public void setTextviewRes(List<TextView> textviews) { //添加文字 //先移除所有的子view removeAllViews(); for (int i = 0; i < textviews.size(); i++) { TextView textView = textviews.get(i); addView(textView); } //重新布局 requestLayout(); }
我们使用控件,调用控件的settextviewres()方法,以textview为例子,
传入添加好的textview的集合(这里可以任意设置,功能需求是什么就可以按照自己的需求去更改)。
这样就完成自定义换行标签