Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 48.Android 標簽TextView的點擊技巧

48.Android 標簽TextView的點擊技巧

編輯:關於Android編程

48.Android 標簽TextView的點擊技巧

Android 標簽TextView的點擊技巧 前言 ClickableSpan源碼 自定義ClickableSpan TagTextView TagTextViewActivity 效果圖 github


前言

在一些圈子性質的頁面裡,每條動態的文本往往都是富文本

其中就有一種摻雜了標簽的富文本內容。如新浪微博的標簽富文本

tag_textview_1

……
……
而且,最重要的是:這些標簽可以點擊。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="tag_textview_2" src="/uploadfile/Collfiles/20151224/20151224091725120.png" title="\" />

這涉及到ClickableSpan的使用。


ClickableSpan源碼

/**
 * If an object of this type is attached to the text of a TextView
 * with a movement method of LinkMovementMethod, the affected spans of
 * text can be selected.  If clicked, the {@link #onClick} method will
 * be called.
 */
public abstract class ClickableSpan extends CharacterStyle implements UpdateAppearance {

    /**
     * Performs the click action associated with this span.
     */
    public abstract void onClick(View widget);

    /**
     * Makes the text underlined and in the link color.
     */
    @Override
    public void updateDrawState(TextPaint ds) {
        ds.setColor(ds.linkColor);
        ds.setUnderlineText(true);
    }
}

ClickableSpan源碼很短,主要是拓展了CharacterStyle的updateDrawState功能,和對外提供了一個onClick方法

我們可以看到ClickableSpan字體的顏色跟隨著linkColor的顏色,默認是有下劃線的

但是新浪微博的那個標簽是沒有下劃線的,顏色也最好是可以自定義的

以上得出:需要自定義一個ClickableSpan


自定義ClickableSpan

public class ClickableSpanNoUnderline extends ClickableSpan {

    private static final String TAG = "ClickableSpan";

    private static final int NO_COLOR = -206;
    private int color;

    private OnClickListener onClickListener;

    public ClickableSpanNoUnderline(int color, OnClickListener onClickListener) {
        super();
        this.color = color;
        this.onClickListener = onClickListener;
    }

    public ClickableSpanNoUnderline(OnClickListener onClickListener) {
        this(NO_COLOR, onClickListener);
    }

    /**
     * Makes the text underlined and in the link color.
     *
     * @param ds
     */
    @Override
    public void updateDrawState(@NonNull TextPaint ds) {
        super.updateDrawState(ds);
        // 設置文字顏色
        if (this.color == NO_COLOR) {
            ds.setColor(ds.linkColor);
        } else {
            ds.setColor(this.color);
        }
        ds.clearShadowLayer();
        // 去除下劃線
        ds.setUnderlineText(false);
        ds.bgColor = Color.TRANSPARENT;
    }

    /**
     * Performs the click action associated with this span.
     *
     * @param widget widget
     */
    @Override
    public void onClick(View widget) {
        if (this.onClickListener != null) {
            this.onClickListener.onClick(widget, this);
        } else {
            Log.w(TAG, "listener was null");
        }
    }

    /**
     * 回調接口,回調自身的onClick事件
     * 告訴外部 是否被點擊
     */
    public interface OnClickListener {
        /**
         * ClickableSpan被點擊
         *
         * @param widget widget
         * @param span   span
         */
        void onClick(View widget, T span);
    }

}

updateDrawState()方法就是設置了顏色和沒有下劃線

OnClickListener:定義了一個泛型回調接口,方便你拓展自己的ClickableSpanNoUnderline:如果你的標簽需要保存一些Id或者Content內容等等,你可以繼承ClickableSpanNoUnderline,實現你自定義的ClickableSpanNoUnderline,然後在View層回調的時候實現ClickableSpanNoUnderline.OnClickListener<你自定義的ClickableSpanNoUnderline>。(模糊的話,可以看底下的 TagTextView 和 TagTextViewActivity)


TagTextView

這裡就隨便寫一個自定義TextView,將剛才的ClickableSpanNoUnderline用上。

public class TagTextView extends TextView {

    private ClickableSpanNoUnderline.OnClickListener onTagClickListener;

    public TagTextView(Context context) {
        super(context);
    }

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

    public TagTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TagTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    /**
     * 添加標簽ClickableSpan
     *
     * @param tags    tags
     * @param content content
     * @return SpannableStringBuilder
     */
    public SpannableStringBuilder addTagClickableSpan(ArrayList tags, String content, ClickableSpanNoUnderline.OnClickListener onTagClickListener) {
        this.onTagClickListener = onTagClickListener;
        StringBuilder sbTag = new StringBuilder();
        Map content2TagDict = new HashMap<>();
        /**
         * 添加 #
         */
        if (tags != null && tags.size() > 0) {
            for (Tag tag : tags) {
                sbTag.append("#");
                sbTag.append(tag.getContent());
                sbTag.append("#");
                sbTag.append(" ");
                content2TagDict.put(tag.getContent(), tag);
            }
        }
        int tagLength = sbTag.toString().length();
        sbTag.append(content);

        /**
         * 添加顏色
         */
        SpannableStringBuilder sb = new SpannableStringBuilder(sbTag.toString());
        if (tagLength > 0) {
            String s = sb.toString();
            String[] model = s.split("#");
            for (int i = 0; i < model.length - 1; i++) {
                /**
                 * 過濾 "" 和 " "
                 */
                if ("".equals(model[i]) || " ".equals(model[i])) continue;
                int index = s.indexOf(model[i]);
                int mLength = model[i].length();
                TagClickableSpan span = new TagClickableSpan(0xffFF4081, this.onTagClickListener);
                span.setContent(model[i]);
                Tag tag = content2TagDict.get(model[i]);
                if (tag != null && tag.getId() != null) {
                    span.setId(tag.getId());
                }
                /**
                 * 設置TagClickableSpan
                 */
                sb.setSpan(span, index - 1, index + mLength + 1, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
            }
        }
        return sb;
    }

    /**
     * Tag ClickableSpan
     */
    public class TagClickableSpan extends ClickableSpanNoUnderline {

        private Long id;
        private String content;

        public TagClickableSpan(int color, OnClickListener onClickListener) {
            super(color, onClickListener);
        }

        public TagClickableSpan(OnClickListener onClickListener) {
            super(onClickListener);
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

    }

}

TagTextViewActivity

根據我上面寫的TagTextView,這裡要實現ClickableSpanNoUnderline.OnClickListener

public class TagTextViewActivity extends AppCompatActivity implements ClickableSpanNoUnderline.OnClickListener {

    private TagTextView tagTV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.setContentView(R.layout.activity_tag_textview);
        this.tagTV = (TagTextView) this.findViewById(R.id.tag_text_view_tv);
        this.initData();
    }

    private void initData() {
        ArrayList tags = new ArrayList<>();

        Tag tag1 = new Tag();
        tag1.setId(2601L);
        tag1.setContent("初心不改");
        Tag tag2 = new Tag();
        tag2.setId(2602L);
        tag2.setContent("方能始終");
        Tag tag3 = new Tag();
        tag3.setId(2603L);
        tag3.setContent("Save You From Anything");

        tags.add(tag1);
        tags.add(tag2);
        tags.add(tag3);

        String sign = "這個世上不存在束縛人的枷鎖......Save You From Anything......";
        this.tagTV.setText(this.tagTV.addTagClickableSpan(tags, sign, this));
        // 在單擊鏈接時凡是有要執行的動作,都必須設置MovementMethod對象
        this.tagTV.setMovementMethod(LinkMovementMethod.getInstance());
        // 設置點擊後的顏色,這裡涉及到ClickableSpan的點擊背景
        this.tagTV.setHighlightColor(0xff8FABCC);
    }

    /**
     * ClickableSpan被點擊
     *
     * @param widget widget
     * @param span   span
     */
    @Override
    public void onClick(View widget, TagTextView.TagClickableSpan span) {
        ToastUtil.show(this, span.getId() + ":" + span.getContent(), Toast.LENGTH_SHORT);
    }

}

效果圖

tag_textview_3


github

覺得代碼不全的,可以去github裡的NO.31。當然也求Star,T T。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved