SpannableStringBuilder导致ellipsize失效(两者冲突)

来源:互联网 发布:win7新增打印机usb端口 编辑:程序博客网 时间:2024/06/16 08:48

这是一个自定义的控件,解决SpannableStringBuilder与ellipsize属性冲突的BUG,适用于ListView等有复用的列表里面,效果图在最底部。

package com.laka.jiawawa.ui.widget;import android.content.Context;import android.graphics.Canvas;import android.support.v7.widget.AppCompatTextView;import android.text.Spannable;import android.text.SpannableStringBuilder;import android.text.style.AbsoluteSizeSpan;import android.text.style.ForegroundColorSpan;import android.util.AttributeSet;import com.laka.jiawawa.R;import com.laka.jiawawa.util.Log;import com.laka.jiawawa.util.ResourceHelper;import com.laka.jiawawa.util.Utils;import java.util.HashMap;/** * @Author Lyf * @CreateTime 2017/12/12 * @Description **/public class SpannableTextView extends AppCompatTextView {    private String mOriginalText; // 原文本    private final String mEllipsizedString = "..."; // 省略文本    private boolean isEllipsized = false; // 是否有添加过省略字符    private String mExchangeCoins = null; // 追加的部分文本(样式与主文本不同)    // 设置部分字体的大小、颜色    private AbsoluteSizeSpan mAbsoluteSizeSpan;    private ForegroundColorSpan mForegroundColorSpan;    private SpannableStringBuilder mSpannableStringBuilder;    // 保存已求得的最佳省略文本,Key是原文本,Value是最佳省略文本    private HashMap<String, String> mEllipsizedMap = new HashMap<>();    public SpannableTextView(Context context) {        super(context);        initView();    }    public SpannableTextView(Context context, AttributeSet attrs) {        super(context, attrs);        initView();    }    public SpannableTextView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView();    }    private void initView(){        mSpannableStringBuilder = new SpannableStringBuilder();        mForegroundColorSpan = new ForegroundColorSpan(ResourceHelper.getColor(R.color.colorFFC038));        mAbsoluteSizeSpan = new AbsoluteSizeSpan((int) (11 * getContext().getResources().getDisplayMetrics().density + 0.5f));    }    /**     * @param exchangeCoins 追加的部分文本(样式与主文本不同)     */    public void setExchangeCoins(String exchangeCoins) {        // list 复用item时,需要重置状态        isEllipsized = false;        if (Utils.isNotEmpty(exchangeCoins)) {            this.mExchangeCoins = exchangeCoins;            // 求得原文本            mOriginalText = getText() + mExchangeCoins;            // 如果有最佳的省略文本,就直接设置.            if (mEllipsizedMap.get(mOriginalText) != null) {                setText(mEllipsizedMap.get(mOriginalText));            } else {                setText(mOriginalText);            }            invalidate();        }    }    @Override    protected void onDraw(Canvas canvas) {        // 有设置追加文本的,才进行计算        if (Utils.isNotEmpty(mExchangeCoins)) {            CharSequence charSequence = getText();            // 重置状态            mSpannableStringBuilder.clear();            // 追加部分文本的长度            int length = mExchangeCoins.length();            // 被省略的文本的长度            int ellipsisCount = getLayout().getEllipsisCount(getLineCount() - 1);            // 如果省略的文本长度大于0并且当前原文本没有对应的最佳省略文本,则进行计算            if (ellipsisCount > 0 && mEllipsizedMap.get(mOriginalText) == null) {                // 是否有添加过省略字符                if (isEllipsized) {                    //消除被省略掉的文本,并以mEllipsizedString显示                    charSequence = deleteEllipsizeText(charSequence,ellipsisCount,length);                } else {                    // 已添加省略字符                    charSequence = setEllipsizedString(charSequence,length);                }            } else {                // 设置文本                charSequence = (charSequence.subSequence(0, charSequence.length() - length)) + mExchangeCoins;                // 保存最佳省略文本                mEllipsizedMap.put(mOriginalText,charSequence.toString());            }            // 设置样式            setSpannable(charSequence,length);        }        super.onDraw(canvas);    }    /**     * 消除被省略掉的文本,并以mEllipsizedString显示     */    private String  deleteEllipsizeText(CharSequence charSequence , int ellipsisCount ,int length) {        // 获取主标题(不包含追加文本)        charSequence = charSequence.subSequence(0, charSequence.length() - length);        //Log.log("削减前="+charSequence);        // 循环,从省略字符左右不断削减字符,直到被省略的字符数为0.        while (ellipsisCount > 0){            int midIndex = charSequence.toString().indexOf(mEllipsizedString);            // 省略字符的左边            int startLength = charSequence.subSequence(0, midIndex).length();           // Log.log("省略符左边的文本="+charSequence.subSequence(0, midIndex));            // 省略字符的右边            int endLength = charSequence.subSequence(midIndex + 3, charSequence.length()).length();           // Log.log("省略符右边的文本="+charSequence.subSequence(midIndex + 3, charSequence.length()));            // 省略字符的左边的文本大于右边的,则削减左边的文本            if (startLength >= endLength) {               // Log.log("左边的文本大于右边");                charSequence = charSequence.subSequence(0, midIndex - 1).toString() + charSequence.subSequence(midIndex , charSequence.length()).toString();            } else {              //  Log.log("右边的文本大于左边");                // 省略字符的右边的文本大于左边的,则削减右边的文本                charSequence = charSequence.subSequence(0, midIndex + 3).toString() + charSequence.subSequence(midIndex + 4, charSequence.length()).toString();            }            --ellipsisCount;           // Log.log("削减后(循环中)="+charSequence);        }        //Log.log("削减后(循环已结束,最终结果)="+charSequence);        // 削减完毕,将追加部分添加回来        return charSequence + mExchangeCoins;    }    /**     * 已添加省略字符     */    private String setEllipsizedString(CharSequence charSequence , int length) {        isEllipsized = true;        // 求得主标题的长度(不包含追加文本)        int middle = (charSequence.length() -length) / 2;        // 去掉主标题中间四字个字符换成省略字符        String startTemp = charSequence.subSequence(0, middle - 2) + mEllipsizedString;        return startTemp + charSequence.subSequence(middle + 2, charSequence.length());    }    /**     *  设置样式     *  @param mExchangeCoinsLength 追加文本的长度     */    private void setSpannable(CharSequence charSequence ,int mExchangeCoinsLength) {        // 设置文本        mSpannableStringBuilder.append(charSequence);        int end = mSpannableStringBuilder.toString().trim().length();        int start = end - mExchangeCoinsLength;        mSpannableStringBuilder.setSpan(mForegroundColorSpan, start, end,                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);        mSpannableStringBuilder.setSpan(mAbsoluteSizeSpan, start, end, Spannable.                SPAN_EXCLUSIVE_EXCLUSIVE);        setText(mSpannableStringBuilder);    }}

这是运行后的效果

阅读全文
0 0
原创粉丝点击