最近做了一个小的demo,使用RecyclerView,item要求显示一段文字,文字包含点击事件,结果发现,超链接的点击事件和RecyclerView的点击事件发生冲突,于是上网搜索相关问题,走了一些弯路,最后在国外的网站发现解决方法,
以下就是发现答案的原网站:http://stackoverflow.com/questions/8558732/listview-textview-with-linkmovementmethod-makes-list-item-unclickable。
以下是解决该问题的步骤:
1. 自定义TextView,定义一个linkHit去控制当前TextView的onTouchEvent的返回值,用于判断是否由TextView来处理当前的点击事件。
2. 自定义linkMovementMethod,并重写它onTouchEvent方法,根据不同情况考虑返回值。
如果点击的是超链接的部分,则selection继续被选中,并且把自定义textView的linkHit设置为true,textView的onTouchEvent返回true,即处理当前点击事件。
如果是点击的是非超链接的部分,即把当前selection给移除掉,textView的onTouchEvent返回false,即不处理当前点击事件,那么这时候就会调用我们定义的RecyclerView他的item的点击事件。
public class LinkTextView extends TextView {
boolean dontConsumeNonUrlClicks = true;
boolean linkHit;
public LinkTextView(Context context) {
super(context);
}
public LinkTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LinkTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public LinkTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
linkHit = false;
boolean res = super.onTouchEvent(event);
if (dontConsumeNonUrlClicks)
return linkHit;
return res;
}
public void setTextViewHTML(String html) {
CharSequence sequence = Html.fromHtml(html);
SpannableStringBuilder strBuilder =
new SpannableStringBuilder(sequence);
setText(strBuilder);
}
public static class LocalLinkMovementMethod extends LinkMovementMethod {
static LocalLinkMovementMethod sInstance;
public static LocalLinkMovementMethod getInstance() {
if (sInstance == null)
sInstance = new LocalLinkMovementMethod();
return sInstance;
}
@Override
public boolean onTouchEvent(TextView widget,
Spannable buffer, MotionEvent event) {
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = buffer.getSpans(
off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
} else if (action == MotionEvent.ACTION_DOWN) {
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
}
if (widget instanceof LinkTextView) {
((LinkTextView) widget).linkHit = true;
}
return true;
} else {
Selection.removeSelection(buffer);
Touch.onTouchEvent(widget, buffer, event);
return false;
}
}
return Touch.onTouchEvent(widget, buffer, event);
}
}
}
3. 布局使用自定义的textView,并且将该textView的focusable和clickable都设置为true。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<test.myapplication.LinkTextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:padding="20dp"
android:text="TextView" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="2dp"
android:background="#000" />
</LinearLayout>
4. 用法同普通textView添加超链接一致,在设置setMovementMethod方法时,使用我们自定义的linkMovementMethod。我把整个Adapter代码贴出来。
public class ListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private LayoutInflater inflater;
private static Context mContext;
List<String> data = null;
public ListAdapter(Context context, List<String> data) {
this.mContext = context;
inflater = LayoutInflater.from(mContext);
this.data = data;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = inflater.inflate(R.layout.item_list, parent, false);
return new ItemViewHolder(v);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
SpannableString sp = new SpannableString(data.get(position));
sp.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(mContext, "超链接点击事件", Toast.LENGTH_SHORT).show();
}
}, 2, 10, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
((ItemViewHolder) holder).txt.setText(sp);
((ItemViewHolder) holder).txt.setMovementMethod(LinkTextView.LocalLinkMovementMethod.getInstance());
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
public static class ItemViewHolder extends RecyclerView.ViewHolder {
LinkTextView txt;
public ItemViewHolder(View convertView) {
super(convertView);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//每个item的点击事件
Intent intentLogin = new Intent(mContext, RatingBarActivity.class);
mContext.startActivity(intentLogin);
}
});
txt = (LinkTextView) convertView.findViewById(R.id.textView);
}
}
}
以上就是解决textView超链接点击事件和RecyclerView的每个item的点击事件冲突问题,希望对大家有所帮助!