需求背景:
1,业务需求想要商品的标题最多展示两行,超过的文本内容...
2,同时头部可能存在标签,尾部也可能存在标签,并且标签可能多个。
3,标签存在图片类型,图片后台配置url。
对于我这种新手,当时看到这种需求心中就知道不妙,看似很麻烦,其实一点也不简单!
本着能百度就百度的原则,赶紧各种搜索,没想到百度都让我点烂了,也没有找到符合要求的文章。
无奈,只能自己手搓...
整理思路:
众所周知,实现这种标签的方式,最方便的就是使用SpannableStringBuilder。
这种方式以TagTextView 为代表的三方控件,差一点就满足我的需求。但是当存在MaxLines 的时候,后置的标签便无法显示,这种以SpannableStringBuilder 的方式我也不知道怎么加载url图片。
折腾了半天都不行,无奈放弃。
本想自定义View drawBitmap、drawText 全都给他画出来!但这种方式我依然不知道怎么让图片类型的Tag加载url图片。
这时想打业务的心都有了!大不了小爷不干了!但看了看卡里的余额....哎,生活多艰。
于是我苦思冥想,终于灵光一闪!!!
自定义一个ViewGroup 计算文本和Tag的宽度,然后addView不就可以了!
正文:
经过一系列的折腾,我实现了以下样式,总算满足了需求:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.dev.kit.testapp.R;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class CustomTagTextView extends LinearLayout {
private int horizontalSpace = 20;
private int content_width;
private boolean measLayout = false;
private List<BeforeTagsBean> before;
private List<BeforeTagsBean> after;
private String text;
private int textColor;
private float textSize;
public CustomTagTextView(Context context) {
this(context,null);
}
public CustomTagTextView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public CustomTagTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.setOrientation(VERTICAL);
if (attrs != null) {
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.CustomTagTextView);
textColor = typedArray.getColor(R.styleable.CustomTagTextView_text_Color, Color.parseColor("#FFFFFF"));
textSize = typedArray.getDimension(R.styleable.CustomTagTextView_text_Size, 16);
horizontalSpace = typedArray.getDimensionPixelSize(R.styleable.CustomTagTextView_tag_Spacing, 20);
Log.e("###", "textSize:" + textSize);
typedArray.recycle();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
content_width = MeasureSpec.getSize(widthMeasureSpec); //获取宽的尺寸
Log.e("###", "宽的尺寸:" + content_width);
if (measLayout) {
measLayout = false;
measTagAndText();
}
}
public void setTagAndText(List<BeforeTagsBean> before, List<BeforeTagsBean> after, String text) {
measLayout = true;
this.before = before;
this.after = after;
this.text = text;
}
private void measTagAndText() {
int beforeWidth = 0;
int afterWidth = 0;
List<View> beforeViews = new ArrayList();
List<View> aferViews = new ArrayList();
if (before != null && before.size() > 0) {
for (int i = 0; i < before.size(); i++) {
//标签类型,1商品来源标签,2功能属性标签,3活动标签(tupian)
if (TextUtils.equals("3", before.get(i).tagType)) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.image_layout, this, false);
LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
layoutParams.rightMargin = horizontalSpace;
ImageView imageView = view.findViewById(R.id.iv_tag);
view.measure(0, 0);
Glide.with(getContext()).load("https://pic2.zhimg.com/80/v2-8d3f288feae0e511dee5c3d6735ca999_720w.webp").into(imageView);
int v_width = view.getMeasuredWidth();
beforeWidth += (v_width + horizontalSpace);
beforeViews.add(view);
} else {
View view = LayoutInflater.from(getContext()).inflate(R.layout.item_tag_layout, this, false);
TextView tv_tag = view.findViewById(R.id.tv_tag);
tv_tag.setText(before.get(i).tagDes);
LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
layoutParams.rightMargin = horizontalSpace;
view.measure(0, 0);
int v_width = view.getMeasuredWidth();
beforeWidth += (v_width + horizontalSpace);
beforeViews.add(view);
}
}
}
if (after != null && after.size() > 0) {
for (int i = 0; i < after.size(); i++) {
//标签类型,1商品来源标签,2功能属性标签,3活动标签(tupian)
if (TextUtils.equals("3", before.get(i).tagType)) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.image_layout, this, false);
LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = horizontalSpace;
ImageView imageView = view.findViewById(R.id.iv_tag);
view.measure(0, 0);
Glide.with(getContext()).load("https://pic2.zhimg.com/80/v2-8d3f288feae0e511dee5c3d6735ca999_720w.webp").into(imageView);
int v_width = view.getMeasuredWidth();
afterWidth += (v_width + horizontalSpace);
aferViews.add(view);
} else {
View view = LayoutInflater.from(getContext()).inflate(R.layout.item_tag_layout, this, false);
TextView tv_tag = view.findViewById(R.id.tv_tag);
tv_tag.setText(before.get(i).tagDes);
LinearLayout.LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = horizontalSpace;
view.measure(0, 0);
int v_width = view.getMeasuredWidth();
afterWidth += (v_width + horizontalSpace);
aferViews.add(view);
}
}
}
TextView textView = new TextView(getContext());
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX,textSize);
textView.setTextColor(textColor);
Paint paint = textView.getPaint();
float textWidth = paint.measureText(text);
Rect rect = new Rect();
paint.getTextBounds(text, 0, text.length(), rect);
// Log.e(rect.width() + "###", "textWidth:" + textWidth);
float tag_text_width = beforeWidth + afterWidth + textWidth;
// Log.e("###", "内容宽度:" + tag_text_width + ",容器宽度:" + content_width);
if (tag_text_width > content_width) { //前后标签加文字的宽度大于了容器宽度
LinearLayout linearLayout = new LinearLayout(getContext());
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.setGravity(Gravity.CENTER_VERTICAL);
if (beforeWidth + textWidth > content_width) {//前标签加文字的宽度大于了容器宽度
for (int i = 0; i < beforeViews.size(); i++) {
linearLayout.addView(beforeViews.get(i));
}
int halfTextLength = text.length() / 2;
String line1 = text.substring(0, halfTextLength);
float halfTextWidth = paint.measureText(line1);
// Log.e("###", halfTextWidth + "line1 = " + line1 + ",halfTextLength=" + (content_width - beforeWidth));
if (halfTextWidth <= (content_width - beforeWidth)) {
for (int i = halfTextLength; i < text.length(); i++) {
line1 = text.substring(0, i);
float autoWidth = paint.measureText(line1);
// Log.e("###", "line1 = " + line1 + ",autoWidth=" + autoWidth);
if (autoWidth >= (content_width - beforeWidth)) {
if (autoWidth > (content_width - beforeWidth)) {
line1 = text.substring(0, i - 1);
}
break;
}
}
} else {
for (int i = halfTextLength; i > 0; i--) {
line1 = text.substring(0, i);
float autoWidth = paint.measureText(line1);
// Log.e("###", "line1# = " + line1 + ",autoWidth=" + autoWidth);
if (autoWidth <= (content_width - beforeWidth)) {
break;
}
}
}
textView.setMaxLines(1);
textView.setText(line1);
linearLayout.addView(textView);
addView(linearLayout);
LinearLayout line2 = new LinearLayout(getContext());
line2.setOrientation(LinearLayout.HORIZONTAL);
line2.setGravity(Gravity.CENTER_VERTICAL);
TextView line2Text = new TextView(getContext());
line2Text.setMaxLines(1);
line2Text.setEllipsize(TextUtils.TruncateAt.END);
line2Text.setMaxWidth(content_width - afterWidth);
line2Text.setText(text.replace(line1, ""));
line2Text.setTextSize(TypedValue.COMPLEX_UNIT_PX,textSize);
line2Text.setTextColor(textColor);
line2.addView(line2Text);
for (int i = 0; i < aferViews.size(); i++) {
line2.addView(aferViews.get(i));
}
addView(line2);
} else {//前标签加文字的宽度小于等于容器宽度
for (int i = 0; i < beforeViews.size(); i++) {
linearLayout.addView(beforeViews.get(i));
}
textView.setMaxLines(1);
textView.setText(text);
linearLayout.addView(textView);
addView(linearLayout);
if (aferViews.size() > 0) {//有了后置标签,才有后续操作
LinearLayout line2 = new LinearLayout(getContext());
line2.setOrientation(LinearLayout.HORIZONTAL);
line2.setGravity(Gravity.CENTER_VERTICAL);
float idleWidth = content_width - (beforeWidth + textWidth);
if (idleWidth > 0) {//放进了标签文字后,还剩余空间
Iterator<View> iterator = aferViews.iterator();
while (iterator.hasNext()) {
View view = iterator.next();
int view_width = view.getMeasuredWidth();
// Log.e("###", "view width = " + view_width);
if (view_width <= idleWidth) {
linearLayout.addView(view);
iterator.remove();
idleWidth -= view_width;
} else {
break;
}
}
}
for (int i = 0; i < aferViews.size(); i++) {
line2.addView(aferViews.get(i));
}
addView(line2);
}
}
} else {//前后标签加文字一行就可以容纳
LinearLayout linearLayout = new LinearLayout(getContext());
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.setGravity(Gravity.CENTER_VERTICAL);
for (int i = 0; i < beforeViews.size(); i++) {
linearLayout.addView(beforeViews.get(i));
}
textView.setMaxLines(1);
textView.setText(text);
linearLayout.addView(textView);
for (int i = 0; i < aferViews.size(); i++) {
linearLayout.addView(aferViews.get(i));
}
addView(linearLayout);
}
}
}
<declare-styleable name="CustomTagTextView"> <attr name="text_Color" format="color"/> <attr name="text_Size" format="dimension"/> <attr name="tag_Spacing" format="dimension"/> </declare-styleable>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/iv_tag" android:layout_width="20dp" android:layout_height="20dp" android:src="@mipmap/ic_launcher"/> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/tv_tag" android:textColor="@color/color_white" android:background="@drawable/tag_bg_shape" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="2dp" android:paddingRight="2dp" android:text="asdasd"/> </RelativeLayout>
CustomTagTextView auto = findViewById(R.id.auto); List<BeforeTagsBean> before = new ArrayList<>(); before.add(new BeforeTagsBean("本省市","1")); before.add(new BeforeTagsBean("集团","2")); before.add(new BeforeTagsBean("集团","3")); List<BeforeTagsBean> after = new ArrayList<>(); after.add(new BeforeTagsBean("集团","1")); after.add(new BeforeTagsBean("本省市","2")); after.add(new BeforeTagsBean("集团","3")); String str = "你时常说要找一条出路,想要一些不会腐坏的温暖。我们随风穿行过时光边缘的洞,最终会像鸟一样长出翅膀,飞翔起来。你时常说你只是一个封闭的过客,不愿在任何地方眷恋停留。因为害怕动荡不安的流离,挣扎着却无能为力。"; String str1 = "你时常说要找一条出路,想要一些不会腐坏的温暖。我们随风穿行过时光边缘的洞。"; String str2 = "你时常说要找一条出路,想要一些不会腐坏的"; String str3 = "你时常说要找一条出路,想要"; auto.setTagAndText(before,after,str3);
所有的代码都在这里了,内容很简单,目前只是粗略的实现。
大概思路就是这样,如果需要更多行,在以上的代码中稍做更改就可实现。
希望对和我一样遇到这种麻烦的需求的小伙伴,有所帮助。
结束。