前后可添加标签的TextView

需求背景:

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);

所有的代码都在这里了,内容很简单,目前只是粗略的实现。

大概思路就是这样,如果需要更多行,在以上的代码中稍做更改就可实现。

希望对和我一样遇到这种麻烦的需求的小伙伴,有所帮助。

结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值