最近做了一個小的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的點選事件沖突問題,希望對大家有所幫助!