This is what we want to achieve. First of all, I want to introduce a project on github, https://github.com/nimengbo/TextViewSpanClickable
This project is to achieve this effect. Here I'm just going to make an introduction of its use
/**
* Created by Abner on 15/6/17.
* QQ 230877476
* Email nimengbo@gmail.com
* Alternatively, each item can be clicked
*/
@SuppressLint("AppCompatCustomView")
public class TopicTextView<T> extends TextView {
private TopicTextView instance;
private Context mContext;
private StyleSpan boldSpan;
private ForegroundColorSpan colorSpan;
private TextTopicClickListener<T> textTopicClickListener;
public void setTextTopicClickListener(TextTopicClickListener<T> textTopicClickListener) {
this.textTopicClickListener = textTopicClickListener;
}
public TopicTextView(Context context) {
super(context);
mContext = context;
initView();
}
public TopicTextView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
initView();
}
public TopicTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
initView();
}
private void initView() {
instance = this;
setMovementMethod(LinkMovementMethod.getInstance());
setHighlightColor(getResources().getColor(R.color.transparent));
boldSpan = new StyleSpan(Typeface.BOLD);
colorSpan = new ForegroundColorSpan(getResources().getColor(R.color.gray_bbbbbb));
}
private TextBlankClickListener listener;
public void setListener(TextBlankClickListener listener) {
this.listener = listener;
}
private int mStart = -1;
private int mEnd = -1;
private android.os.Handler handler = new android.os.Handler();
//count
private int leftTime;
private Runnable countDownRunnable = new Runnable() {
public void run() {
leftTime--;
if (leftTime == -1) {
// Trigger long press event
if (listener != null) {
listener.onLongClick(instance);
}
} else {
//If 100 ms is executed for more than 500 ms, long press will be triggered
handler.postDelayed(this, 100);
}
}
};
private boolean isMove = false;
private float lastX;
private float lastY;
private int originalStart = -1;
private int originalEnd = -1;
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = super.onTouchEvent(event);
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
if (action == MotionEvent.ACTION_DOWN) {
lastX = event.getX();
lastY = event.getY();
isMove = false;
} else if (action == MotionEvent.ACTION_MOVE) {
float distanceX = Math.abs(lastX - event.getX());
float distanceY = Math.abs(lastY - event.getY());
if (distanceX > 1.5f || distanceY > 1.5f) {
isMove = true;
}
}
x -= getTotalPaddingLeft();
y -= getTotalPaddingTop();
x += getScrollX();
y += getScrollY();
Layout layout = getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
CharSequence text = getText();
if (TextUtils.isEmpty(text) || !(text instanceof Spannable)) {
return result;
}
Spannable buffer = (Spannable) text;
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_DOWN) {
mStart = buffer.getSpanStart(link[0]);
mEnd = buffer.getSpanEnd(link[0]);
if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(Color.GRAY), mStart, mEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mStart = -1;
mEnd = -1;
}
} else if (action == MotionEvent.ACTION_MOVE) {
if (isMove) {
if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mStart = -1;
mEnd = -1;
}
}
}
return true;
} else {
if (mStart >= 0 && mEnd >= mStart) {
buffer.setSpan(new BackgroundColorSpan(Color.TRANSPARENT), mStart, mEnd,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mStart = -1;
mEnd = -1;
}
if (action == MotionEvent.ACTION_DOWN) {
setBackgroundColor(Color.GRAY);
//Start counting
leftTime = 5;
handler.post(countDownRunnable);
return true;
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
setBackgroundColor(Color.TRANSPARENT);
//If there is no call, long press to call and click the whole monitor
if (leftTime > -1) {
leftTime = 10;
handler.removeCallbacks(countDownRunnable);//Remove statistics
if (listener != null && !isMove) {
listener.onBlankClick(this);
}
}
} else if (action == MotionEvent.ACTION_MOVE) {
if (isMove) {
setBackgroundColor(Color.TRANSPARENT);
}
}
Selection.removeSelection(buffer);
return false;
}
}
/**
* Set your likes
*
* @param topics
* @return
*/
public void setTopics(List<LikeUserAppDto> topics) {
setText("");
int length = topics.size();
//Set the default blue and white heart-shaped picture in front of liker
SpannableStringBuilder defaultStringBuilder = new SpannableStringBuilder("#");
Drawable drawable = mContext.getResources().getDrawable(R.mipmap.blue_heart);
drawable.setBounds(0, 5, 40, 40);
HouseImageSpan imageSpan = new HouseImageSpan(drawable);
defaultStringBuilder.setSpan(imageSpan, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
append(defaultStringBuilder);
//Display the picture of personal portrait, which can be changed according to your own needs
for (int i = 0; i < length; i++) {
String topic;
if (i == length - 1) {
topic = " " + topics.get(i).getNickname();
} else {
topic = " " + topics.get(i).getNickname() + " ";
}
Drawable drawable1 = mContext.getResources().getDrawable(R.mipmap.moren_head_2);
drawable1.setBounds(15, 0, 63, 48);
HouseImageSpan imageSpan1 = new HouseImageSpan(drawable1);
final SpannableStringBuilder imgStringBuilder = new SpannableStringBuilder("#");
imgStringBuilder.setSpan(imageSpan1, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
if (StringHelper.isNotEmpty(topics.get(i).getLogo())) {
if (topics.get(i).getBitmap() != null) {
Bitmap bitmap = BitmapHelper.getImageSmall(topics.get(i).getBitmap(), 120, 120);
Bitmap bitmap2 = BitmapHelper.toRoundBitmap(bitmap);
//Set the display position of the head picture
Drawable drawable2 = DrawableToUriHelper.getInstance().bitmapToDrawable(bitmap2);
drawable2.setBounds(15, 0, 63, 48);
HouseImageSpan imageSpan2 = new HouseImageSpan(drawable2);
imgStringBuilder.setSpan(imageSpan2, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
append(imgStringBuilder);
}
}
//Set the nickname of the person who likes
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(topic);
//Span of rich text Click event
TopicSpan topicSpan = new TopicSpan(topics.get(i), getResources(), textTopicClickListener);
spannableStringBuilder.setSpan(topicSpan, 0, topic.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
append(spannableStringBuilder);
}
}
}
The HouseImageSpan mentioned in the code can be accessed through https://blog.csdn.net/zhourui_1021/article/details/80996165 Come to know.
This is the custom TextView used to achieve this effect. I have changed it to a generic form to facilitate my own use. The TopicSpan code used is as follows
/**
* Created by Abner on 15/6/17.
* QQ 230877476
* Email nimengbo@gmail.com
*/
public class TopicSpan<T> extends ClickableSpan {
private T topic;
private StyleSpan boldSpan;
private Resources resources;
private TextTopicClickListener<T> topicClickListener;
public TopicSpan(T topic, Resources resources, TextTopicClickListener<T> listener) {
this.topic = topic;
this.resources = resources;
topicClickListener = listener;
}
@Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
ds.setColor(resources.getColor(R.color.blue_1779ff));
}
@Override
public void onClick(View widget) {
if(topicClickListener != null){
topicClickListener.onTopicClick(widget,topic);
}
}
}```
//I also passed in generics for the code of this class to be used by the supplier. The code of TextTopicClickListener is as follows:
/**
* Created by Abner on 15/6/17.
* QQ 230877476
* Email nimengbo@gmail.com
*/
public interface TextTopicClickListener< T > {
void onTopicClick(View view, T topic);
}
TextBlankClickListener Code::
/**
* Created by Abner on 15/6/17.
* QQ 230877476
* Email nimengbo@gmail.com
*/
public interface TextBlankClickListener {void onBlankClick(View view); void onLongClick(View view);
}
This is the code involved. Here's how to use it: Writing in layout
< own location.topica lt extview
android:id="@+id/tv_community_like"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/px_15"
android:layout_marginTop="@dimen/px_5"
android:gravity="center_vertical"
android:textColor="@color/blue_1779ff"
android:textSize="@dimen/px_24" />
tv_community_like.setTextTopicClickListener(new TextTopicClickListener() {
@Override
public void onTopicClick(View view, the required form topic){
Logic you need
}
});
//To set the content displayed in TextView, setTopics is the method to set the content in custom TextView
tv_community_like.setTopics(item.getLikes());
"`
This is that the whole provision of click event of liker can be realized.
My technology is relatively poor, so I want to sort out this function in the hope that it can help everyone, and in the second place, it can help me to use it conveniently in the future. Welcome to comment and correct.