編輯:關於Android編程
Android 標簽TextView的點擊技巧 前言 ClickableSpan源碼 自定義ClickableSpan TagTextView TagTextViewActivity 效果圖 github
在一些圈子性質的頁面裡,每條動態的文本往往都是富文本。
其中就有一種摻雜了標簽的富文本內容。如新浪微博的標簽富文本。
……
……
而且,最重要的是:這些標簽可以點擊。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="tag_textview_2" src="/uploadfile/Collfiles/20151224/20151224091725120.png" title="\" />
這涉及到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。
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)
這裡就隨便寫一個自定義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;
}
}
}
根據我上面寫的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);
}
}
覺得代碼不全的,可以去github裡的NO.31。當然也求Star,T T。
Android4.4新特性,系統狀態欄一體化。 實現的步驟主要有以下幾點: 1.android4.4 以上版本 2.設置app全屏: 方法:在AndroidManifes
前段時間項目中用到了下拉刷新功能,之前在網上也找到過類似的demo,但這些demo的質量參差不齊,用戶體驗也不好,接口設計也不行。最張沒辦法,終於忍不了了,自己就寫了一個
1、概述 上一篇已經基本給大家介紹了如何自定義ViewGroup,如果你還不了解,請查看:Android 手把手教您自定ViewGroup ,本篇將使用上篇
偶爾看到之前寫過的代碼,感覺好多東西幾乎在很多項目中都要用到,雖然每個項目的需求和設計都不同,不過實現的效果都是一樣的,可能只是數據格式和一些顏色等的細微差距.但是有的時