android跨度点击事件

Posted

技术标签:

【中文标题】android跨度点击事件【英文标题】:android span click event 【发布时间】:2013-03-19 22:27:16 【问题描述】:

好的。这些是我的问题。

    我需要使用正则表达式来过滤除字母以外的所有内容,然后我需要将找到的单词包含在 $word 标记中。 有了这个 str = str.replaceAll(pattern, "$0");。 现在我正在过滤所有正确的元素(标点符号、数字等),但它将每个单词中的每个字母都包含在 a 标签中而不是单词中。那么如何使用正则表达式将字母组合成一个单词呢?

from "(a tag open)t(a close)(a tag open)h(a close)(a tag open)i(a close)(a tag open)s(a close)(a tag open) i(a close)(a tag open)s(a close)(a tag open)w(a close)(a tag open)r(a close)(a tag open)o(a close)(a tag open) n(a close)(a tag open)g(a close)";

到:

"(a tag open)this(a close) (a tag open)is(a close) (a tag open)right(a close)";

然后我让它们可点击,我需要捕捉点击事件并在点击的单词上获取屏幕上的位置,因为我想使用点击的事件使工具提示显示在点击的单词下方。谢谢你的帮助。

公共类 MainActivity 扩展 Activity

public String text = "This is just a sentence to test you. 23 this is another number23!g?";
public TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    text = explode(text);

    tv = (TextView) findViewById(R.id.tv1);

    tv.setLinksClickable(true);
    tv.setMovementMethod(LinkMovementMethod.getInstance());

    Spanned article = html.fromHtml(text, null, null);
    setHTML(article);



public void setHTML(Spanned html) 
      SpannableString message = new SpannableString(html.toString());
      Object[] spans = html.getSpans(0, html.length(), Object.class);
      for (Object span : spans) 
         int start = html.getSpanStart(span);
         int end = html.getSpanEnd(span);
         int flags = html.getSpanFlags(span);
         if (span instanceof URLSpan) 
            URLSpan urlSpan = (URLSpan) span;
            span = new CallbackSpan(urlSpan.getURL());
         
         message.setSpan(span, start, end, flags);
      
      tv.setText(message);
   
    public String explode(String str)  
      String pattern = "([a-zA-Z])";
      str = str.replaceAll(pattern, "<a href=\"$0\">$0</a>");
      return str;
    

   private final class CallbackSpan extends ClickableSpan 

      private String m_data;
      private String url_main;

      public CallbackSpan(String url) 
         m_data = url.substring(0);
         url_main = url;

      

      public void onClick(View view) 

          TextView item = (TextView)findViewById(R.id.tv2);
          item.setText(url_main + " was clicked.");
          Log.d("item", url_main);
      
   

【问题讨论】:

我无法清楚地理解这个问题。您有字符串,并且打算单击 textview 中的文本。 首先我有字符串“This is a with numbers 238 66 AND ?? PUNC BL BLA”我想将其转换为“This is span> a with 数字 238 66 AND ?? PUNC BL BLA" 但我得到了这个“This is..... 等" 那么我如何将字母组合成一个单词 您想让 textview 中的单个作品可点击吗? 是的,但我已经用上面的代码知道了。我可以从每个点击的项目中记录每个不同的单词和我需要的所有详细信息,但它会转换所有字母而不是单词 【参考方案1】:

最新代码,请参阅link form github

message.setSpan(span, start, end, flags);

您需要在设置新跨度之前删除原跨度。 请看下文The onClick() of ClickableSpan is not working for URLSpan?

编辑 您可以通过extends LinkMovementMethod

捕获任何跨度点击事件
    import android.os.Handler;
import android.os.Message;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.widget.TextView;

import java.lang.ref.WeakReference;

public class LinkMovementMethodExt extends LinkMovementMethod 
    public static final int LinkMovementMethod_Down = 1001;
    public static final int LinkMovementMethod_Up = 2002;
    private static LinkMovementMethod sInstance;
    private Class mSpanClass = null;
    private WeakReference<Handler> mWeakReference = null;

    public static MovementMethod getInstance(Handler handler, Class spanClass) 
        if (sInstance == null) 
            sInstance = new LinkMovementMethodExt();
            ((LinkMovementMethodExt) sInstance).mWeakReference = new WeakReference<>(handler);
            ((LinkMovementMethodExt) sInstance).mSpanClass = spanClass;
        
        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);
            /**
             * get you interest span
             */
            Object[] spans = buffer.getSpans(off, off, mSpanClass);
            if (spans.length != 0) 
                if (action == MotionEvent.ACTION_DOWN) 
                    Selection.setSelection(buffer, buffer.getSpanStart(spans[0]), buffer.getSpanEnd(spans[0]));
                    MessageSpan obj = new MessageSpan();
                    obj.setObj(spans);
                    obj.setView(widget);
                    Handler handler = mWeakReference.get();
                    if (handler != null) 
                        Message message = handler.obtainMessage();
                        message.obj = obj;
                        message.what = LinkMovementMethod_Down;
                        message.sendToTarget();
                        return true;
                    
                    return false;
                 else if (action == MotionEvent.ACTION_UP) 
                    Handler handler = mWeakReference.get();
                    if (handler != null) 
                        MessageSpan obj = new MessageSpan();
                        obj.setView(widget);
                        Message message = handler.obtainMessage();
                        message.obj = obj;
                        message.what = LinkMovementMethod_Up;
                        message.sendToTarget();
                        return true;
                    
                    return false;
                
            
        

        return super.onTouchEvent(widget, buffer, event);
    

    public boolean canSelectArbitrarily() 
        return true;
    

    public boolean onKeyUp(TextView widget, Spannable buffer, int keyCode,
                           KeyEvent event) 
        return false;
    

textView.setMovementMethod(LinkMovementMethodExt.getInstance());


编辑“android 开发者” 最好为 LinkMovementMethodExt 类添加 Handler 属性。 您可以捕获作为 Message 对象传递的所有 Spanned。 在 onTouchEvent 方法中截取代码:

Message message = Handler.obtainMessage();
message.obj = buffer.getSpans(off, off, Spanned.class);//get all spanned
message.what = 111;//which value ,it is up to you
message.sendToTarget(); //send message to you target handler

您可以在您的处理程序类中处理预期的处理程序。可能是灵活的处理方式。 希望能帮到你。


上面的textview文字是&lt;a href='/a'&gt;aaaa&lt;/a&gt;123456&lt;a href='/b'&gt;bbbb&lt;/b&gt;7890 我明白你的要求:点击'aaaa',你想要得到它s href value '/a', click 'bbbb',get its href '/b';不要触发在 Web 浏览器中打开的默认操作。 如果我的理解是正确的,你可以这样做:

为 textview 等设置 LinkMovementMethod:textview.setMovementMethod(LinkMovementMethodExt.getInstance(handler, URLSpan.class)); 获取兴趣范围,这里是 URLSpan。 在您的处理程序 handleMessage 方法中,您可以这样做:
private Handler handler = new Handler() 
      public void handleMessage(Message msg) 
          int what = msg.what;
          if (what == 100) 
              Object[] spans = (Object[])msg.obj;
              for (Object span : spans) 
                  if (span instanceof URLSpan) 
                      System.out.println(((URLSpan) span).getURL());
                  
              
          
      ;
  ;

Download demo code

MainActivity 具有 color 属性,您可以根据需要分配哪个颜色值。

怎么办?

Step1,获取当前点击跨度。

Step2,为当前点击范围设置BackgroundColorSpan

【讨论】:

这是一个非常好的解决方案。我可以在单击链接时执行自定义操作,但在链接上仍然具有相同的单击效果(我使用 ClickableSpan)? 我不明白。也许我会更好地解释:假设我有一个 textView ,我从 strings.xml 设置了一个文本,其中有多个链接。我希望捕获对它们中的每一个的点击,以便我自己处理接下来发生的事情,而不是打开网络浏览器的意图。我该怎么做? 你将把处理程序放在哪里并让它超越默认行为?目前我所能看到的只是准备处理程序,但与将其放置在何处并使其工作无关... 我已经编辑了具有处理程序参数的 MovementMethod getInstance() 方法。 @androiddeveloper,我推送最新代码。将链接背景颜色更改为默认颜色 (view.getLinkTextColors().getDefaultColor())【参考方案2】:

假设您想单击文本视图上的单个单词?。我不明白您评论中将所有字母转换为单词。

以下可用于点击个别作品,并以吐司的形式显示。

    public class MainActivity extends Activity 

    TextView _tv;
    String[] each;
    SpannableString ss1;
    Button b;
    EditText et;
    String s;
    @Override
    public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    b= (Button) findViewById(R.id.button1);
    et = (EditText) findViewById(R.id.ed);
    _tv = (TextView) findViewById( R.id.tv );
    b.setOnClickListener(new OnClickListener()
    

    @Override
    public void onClick(View v) 
        // TODO Auto-generated method stub
        s=et.getText().toString();
        _tv.setText("");
        for(int i=0;i<s.length();i++)
        
            each = s.split("\\s+");
        
        for(int i=0;i<each.length;i++)
        
            System.out.println("................"+each[i]);
            ss1=  new SpannableString(each[i]);
            //StyleSpan boldSpan = new StyleSpan( Typeface.BOLD );
            //spannable.setSpan( boldSpan, 41, 52, Spannable.SPAN_INCLUSIVE_INCLUSIVE );
            ss1.setSpan(new MyClickableSpan(each[i]), 0, ss1.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            _tv.append(ss1); 
            _tv.append(" "); 

        
        _tv.setMovementMethod(LinkMovementMethod.getInstance());
    
       );
      
      class MyClickableSpan extends ClickableSpan 
      String clicked;
          public MyClickableSpan(String string) 
    // TODO Auto-generated constructor stub
       clicked =string;
      
      //clickable span
      public void onClick(View textView) 
      //do something


      Toast.makeText(MainActivity.this,clicked ,
        Toast.LENGTH_SHORT).show();
     
     @Override
     public void updateDrawState(TextPaint ds) 
     ds.setColor(Color.BLACK);//set text color 
     ds.setUnderlineText(false); // set to false to remove underline
     
    
    

【讨论】:

@TheMan68 你要找的是这个吗? 不完全因为这仍然带来了所有元素,如数字和可点击的东西。我只定义了单词。这就是为什么我使用正则表达式在单词周围插入 a 标签。谢谢你的帮助

以上是关于android跨度点击事件的主要内容,如果未能解决你的问题,请参考以下文章

点击同时触发两个onclick事件[重复]

如何绑定android点击事件

android 点击事件防抖 防止重复点击

错误:SPAN_EXCLUSIVE_EXCLUSIVE 跨度的长度不能为零

Android中点击事件功能实现示例

如何在内容可编辑的 div 内的嵌套跨度上触发事件?