RecyclerView新增點選事件和textView的超連結點選事件衝突
阿新 • • 發佈:2019-02-06
最近做了一個小的demo,使用RecyclerView,item要求顯示一段文字,文字包含點選事件,結果發現,超連結的點選事件和RecyclerView的點選事件發生衝突,於是上網搜尋相關問題,走了一些彎路,最後在國外的網站發現解決方法,
以下是解決該問題的步驟:
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的點選事件衝突問題,希望對大家有所幫助!