android完美解决ClickableSpan中点击后ListView中item的长按冲突的问题

时间:2022-09-22 18:56:27

项目中碰到一个问题,情景是这样的:

有一个ListView,每个item中有一个TextView,textview实现了LongClick事件 实现复制文本的功能 ,这个TextView中又添加了ClickableSpan,实现了方法onClick。

我的需求是点击ClickableSpan,则响应ClickableSpan事件;长按ClickableSpan效果跟长按TextView应该一样,都响应TextView的LongClick事件。


研究了一下代码,解决方法如下:


package com.youxiake.controls;

import android.app.AlertDialog;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.TextView;
import android.widget.Toast;

import com.youxiake.util.MyLog;

public class TextViewFixTouchConsume extends TextView {
boolean dontConsumeNonUrlClicks = true;
int linkHit;

public OnClickListener onclick;


public void setMyOnClickListener(OnClickListener onclick){
this.onclick=onclick;
}

@Override
public boolean hasFocusable() {
return false;
}

public TextViewFixTouchConsume(Context context) {
super(context);
}

public TextViewFixTouchConsume(Context context, AttributeSet attrs) {
super(context, attrs);
}

public TextViewFixTouchConsume(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}



// @Override
// public void setOnLongClickListener(OnLongClickListener l) {
//
// ClipboardManager cmb =
// (ClipboardManager)getContext().getSystemService(Context.CLIPBOARD_SERVICE);
// cmb.setText(getText().toString().trim());
// Toast.makeText(getContext(), "已复制", Toast.LENGTH_SHORT).show();
//
// };

@Override
public boolean onTouchEvent(MotionEvent event) {

//MyLog.debug_s("onTouchEvent:begin");

boolean res = super.onTouchEvent(event);

//MyLog.debug_s("onTouchEvent:"+res+",linkHit="+linkHit);

return res;
}


public static class DialogCopy {

private static View.OnLongClickListener onLongClickListener;

public static View.OnLongClickListener getInstance() {
if (onLongClickListener == null) {
onLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(final View v) {
AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
builder.setItems(new String[]{"复制"}, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
TextView textView = (TextView) v;
Context context = v.getContext();
String txt = textView.getText().toString();

ClipboardManager cmb = (ClipboardManager) context.getSystemService(context.CLIPBOARD_SERVICE);
if(txt!=null){
cmb.setText(txt);
}
Toast.makeText(context, "已复制", Toast.LENGTH_SHORT).show();
}
}
}).show();

return true;
}
};
}

return onLongClickListener;
}
}


public static class LocalLinkMovementMethod extends LinkMovementMethod {
static LocalLinkMovementMethod sInstance;

public static LocalLinkMovementMethod getInstance() {
if (sInstance == null)
sInstance = new LocalLinkMovementMethod();

return sInstance;
}


private long mActionDownTime = 0;

@Override
public boolean onTouchEvent(TextView widget, Spannable buffer,
MotionEvent event) {
int action = event.getAction();

MyLog.debug_s("action:"+action);

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);

MyLog.debug_s("off:"+off+",link:"+link.length);

if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
if (System.currentTimeMillis() - mActionDownTime < ViewConfiguration.getLongPressTimeout()) {
//MyLog.debug_s("ACTION_UP");
link[0].onClick(widget);
}

} else if (action == MotionEvent.ACTION_DOWN) {
//MyLog.debug_s("ACTION_DOWN");
Selection.setSelection(buffer,
buffer.getSpanStart(link[0]),
buffer.getSpanEnd(link[0]));
mActionDownTime = System.currentTimeMillis();

}else if (action == MotionEvent.ACTION_MOVE) {
//MyLog.debug_s("ACTION_MOVE");
}

return true;
} else {
Selection.removeSelection(buffer);
// MyLog.debug_s("Selection.removeSelection(buffer);");
//Touch.onTouchEvent(widget, buffer, event);
if (action == MotionEvent.ACTION_UP) {
if (System.currentTimeMillis() - mActionDownTime < ViewConfiguration.getLongPressTimeout()) {
if (widget instanceof TextViewFixTouchConsume) {
if(((TextViewFixTouchConsume) widget).onclick!= null){

((TextViewFixTouchConsume) widget).onclick.onClick(widget);
}
}
}

} else if (action == MotionEvent.ACTION_DOWN) {
mActionDownTime = System.currentTimeMillis();
}

return true;
}
}
//return true;
return super.onTouchEvent(widget, buffer, event);
}

}

}