SpannableString中的ClickableSpan和Textview点击事件冲突解决

背景描述:项目中有这样的需求:在展示评论内容的Textview中展示文字,其中包含3种类型数据:
1、普通文字:评论内容或者回复内容。因为这个Textview是展示评论或者回复的,点击后,要展示软键盘(popupwindow等忽略)
2、股票代码:该类型文字显示另一种颜色,并且点击后去到展示webView的activity展示股票网页
3、关联的人名:如:@123,显示不同于普通文字的颜色,点击后去到这个人的个人详情页

出现问题:在用SpannableString中的ClickableSpan的时候,会出现问题:点击了股票代码或者人名后,虽然会跳转,但是,会在跳转过程中出现软键盘,到底目标activity后,软键盘消失。这样展示不美观

解决方法:需要将点击的关键字的点击事件(即:ClickableSpan的点击事件和Textview的点击事件分开)

效果图:
图1:
这里写图片描述

———————————————————————————————————–
图2:
这里写图片描述

——————————————————————————————————–
代码:
1、activity:

package com.chen.customviewdemo.activity;

import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.bean.KeyBean;
import com.chen.customviewdemo.view.MyTextView_1;
import com.chen.customviewdemo.view.MyTextView_2;

import java.util.ArrayList;

/**
 * 一个Textview中,有需要点击后专门处理的关键字,也有Textview自己的点击事件,
 * 如:点击关键字跳转到其他activity中,点击非关键字后出现软键盘
 * 有时候,会出现这样的情况:点击关键字后,跳转过程中,软键盘会弹出一瞬间。影响美观.
 */
public class MainActivity_34_Maching_ClickableSpan extends BaseActivity {

    /**
     * 说明:
     * MyTextView_1:没有对关键字区域专门处理,点击后,非关键字区域还是会得到点击事件
     * MyTextView_2:对关键字区域专门处理,点击后,非关键字区域没有获得点击事件
     * 点击MyTextView_1中的关键字区域去跳转,没有出现软键盘闪现问题。但是项目中确实出现过。建议使用MyTextView_2
     * 这里,为了说明情况,没有使用跳转。而是点击后弹出吐司。
     * 在MyTextView_1中,点击关键字,弹出吐司,并且出现软键盘
     * 在MyTextView_2中,点击关键字,仅弹出吐司,不出现软键盘
     */

    MyTextView_1 my_textview_1;
    MyTextView_2 my_textview_2;


    @Override
    void initview() {
        setContentView(R.layout.activity_main_34);

        my_textview_1 = (MyTextView_1) findViewById(R.id.my_textview_1);
        my_textview_2 = (MyTextView_2) findViewById(R.id.my_textview_2);

        ArrayList<KeyBean> keyBeanList = new ArrayList<KeyBean>();

        keyBeanList.add(new KeyBean("我", "我"));
        keyBeanList.add(new KeyBean("你", "你"));
        keyBeanList.add(new KeyBean("他", "他"));
        keyBeanList.add(new KeyBean("哦", "哦"));
        keyBeanList.add(new KeyBean("哈哈", "哈哈"));
        keyBeanList.add(new KeyBean("605", "605"));
        keyBeanList.add(new KeyBean("@嗯嗯", "嗯嗯"));

        String content = "我们123哈哈哦缴费基数机诶@嗯嗯5623";

        String redStr = "123";


        my_textview_1.insertData(content, redStr, keyBeanList);

        my_textview_1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showKeyBoard();
            }
        });

        my_textview_2.insertData(content, redStr, keyBeanList);

        my_textview_2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showKeyBoard();
            }
        });

    }

    /**
     * 展示软键盘
     */
    public void showKeyBoard() {
        InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        inputManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }

}

2、布局:activity_main_34

<?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="match_parent"
              android:background="#ffffff"
              android:orientation="vertical"
    >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center"
        android:padding="5dp"
        android:text="Activity34_ClickableSpan和Textview点击事件冲突"
        android:textColor="#ec434b"
        android:textSize="20sp"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv_1"
        android:textSize="20sp"/>

    <com.chen.customviewdemo.view.MyTextView_1
        android:id="@+id/my_textview_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:background="#f6f6f6"
        android:padding="10dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginTop="20dp"
        android:background="#000000"
        />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center"
        android:padding="5dp"
        android:text="tv_2"
        android:textSize="20sp"/>

    <com.chen.customviewdemo.view.MyTextView_2
        android:id="@+id/my_textview_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:background="#f6f6f6"
        android:padding="10dp"/>


</LinearLayout>

3、MyTextView_1:没有对关键字区域专门处理,点击后,非关键字区域还是会得到点击事件

package com.chen.customviewdemo.view;

import android.content.Context;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.bean.KeyBean;

import java.util.ArrayList;

public class MyTextView_1 extends TextView {

    private Context context;

    private String toRedWord = "";

    public MyTextView_1(Context context) {
        this(context, null);
    }

    public MyTextView_1(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public MyTextView_1(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        myTextViewInit();
    }

    /**
     * 初始化
     */
    private void myTextViewInit() {

    }

    public void insertData(String str, String redStr, final ArrayList<KeyBean> keyBeanList) {

        toRedWord = redStr;

        //        final SpannableString spannableString = ExpressionUtil.getSpannableString(str, context);
        SpannableString spannableString = new SpannableString(str);
        String content = spannableString.toString();

        //处理文本中的关键字
        if (keyBeanList != null && keyBeanList.size() > 0) {
            for (int i = 0; i < keyBeanList.size(); i++) {
                final String data = keyBeanList.get(i).getContent();
                final String hide_content = keyBeanList.get(i).getHide_content();
                String temp = content;
                int startNew = 0;
                int startOld = 0;
                if (temp.contains(data)) {
                    while (temp.contains(data)) {
                        spannableString.setSpan(new ClickableSpan() {
                                                    @Override
                                                    public void updateDrawState(TextPaint ds) {
                                                        // TODO Auto-generated method stub
                                                        super.updateDrawState(ds);
                                                        ds.setColor(context.getResources().getColor(R.color.linkcolor));
                                                        ds.setUnderlineText(false);
                                                    }

                                                    @Override
                                                    public void onClick(View widget) {
                                                        Toast.makeText(context, hide_content, Toast.LENGTH_SHORT).show();

                                                        //Intent intent = null;
                                                        //if (data.startsWith("@")) {
                                                        //   intent = new Intent(context, PersonActivity.class);
                                                        //} else {
                                                        //    intent = new Intent(context, WebActivity.class);
                                                        //}
                                                        //intent.putExtra("hide_content", hide_content);
                                                        //context.startActivity(intent);

                                                    }

                                                }, startOld + temp.indexOf(data), startOld + temp.indexOf(data) + data.length(),
                                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        setText(spannableString);
                        setMovementMethod(LinkMovementMethod.getInstance());
                        startNew = temp.indexOf(data) + data.length();
                        startOld += startNew;
                        temp = temp.substring(startNew);
                    }
                } else {
                    setText(spannableString);
                }
            }

        } else {
            setText(spannableString);
        }

        //处理要变红的字
        if (!TextUtils.isEmpty(toRedWord)) {
            //只要把关键字变红就行了,不需要加点击事件。如果需要,可以自己加
            String temp = content;
            int startNew = 0;
            int startOld = 0;
            while (temp.contains(toRedWord)) {
                spannableString.setSpan(new ClickableSpan() {

                                            @Override
                                            public void updateDrawState(TextPaint ds) {
                                                // TODO Auto-generated method stub
                                                super.updateDrawState(ds);
                                                ds.setColor(0xffff0000);
                                                ds.setUnderlineText(false);
                                            }

                                            @Override
                                            public void onClick(View widget) {
                                            }

                                        }, startOld + temp.indexOf(toRedWord), startOld + temp.indexOf(toRedWord) + toRedWord.length(),
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                setText(spannableString);
                setMovementMethod(LinkMovementMethod.getInstance());
                startNew = temp.indexOf(toRedWord) + toRedWord.length();
                startOld += startNew;
                temp = temp.substring(startNew);
            }
        } else {
            setText(spannableString);
        }


    }

}

4、MyTextView_2:对关键字区域专门处理,点击后,非关键字区域没有获得点击事件

package com.chen.customviewdemo.view;

import android.content.Context;
import android.text.Layout;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.method.Touch;
import android.text.style.ClickableSpan;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.chen.customviewdemo.R;
import com.chen.customviewdemo.bean.KeyBean;

import java.util.ArrayList;

public class MyTextView_2 extends TextView {

    private Context context;

    private String toRedWord = "";

    public MyTextView_2(Context context) {
        this(context, null);
    }

    public MyTextView_2(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public MyTextView_2(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        myTextViewInit();
    }

    /**
     * 初始化
     */
    private void myTextViewInit() {

    }

    public void insertData(String str, String redStr, final ArrayList<KeyBean> keyBeanList) {

        toRedWord = redStr;

        //        final SpannableString spannableString = ExpressionUtil.getSpannableString(str, context);
        SpannableString spannableString = new SpannableString(str);
        String content = spannableString.toString();

        //处理文本中的关键字
        if (keyBeanList != null && keyBeanList.size() > 0) {
            for (int i = 0; i < keyBeanList.size(); i++) {
                final String data = keyBeanList.get(i).getContent();
                final String hide_content = keyBeanList.get(i).getHide_content();
                String temp = content;
                int startNew = 0;
                int startOld = 0;
                if (temp.contains(data)) {
                    while (temp.contains(data)) {
                        spannableString.setSpan(new ClickableSpan() {
                                                    @Override
                                                    public void updateDrawState(TextPaint ds) {
                                                        // TODO Auto-generated method stub
                                                        super.updateDrawState(ds);
                                                        ds.setColor(context.getResources().getColor(R.color.linkcolor));
                                                        ds.setUnderlineText(false);
                                                    }

                                                    @Override
                                                    public void onClick(View widget) {
                                                        Toast.makeText(context, hide_content, Toast.LENGTH_SHORT).show();

                                                        //Intent intent = null;
                                                        //if (data.startsWith("@")) {
                                                        //     intent = new Intent(context, PersonActivity.class);
                                                        //} else {
                                                        //     intent = new Intent(context, WebActivity.class);
                                                        //}
                                                        //intent.putExtra("hide_content", hide_content);
                                                        //context.startActivity(intent);

                                                    }

                                                }, startOld + temp.indexOf(data), startOld + temp.indexOf(data) + data.length(),
                                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                        setText(spannableString);
                        setMovementMethod(CustomLinkMovementMethod.getInstance());
                        startNew = temp.indexOf(data) + data.length();
                        startOld += startNew;
                        temp = temp.substring(startNew);
                    }
                } else {
                    setText(spannableString);
                }
            }

        } else {
            setText(spannableString);
        }

        //处理要变红的字
        if (!TextUtils.isEmpty(toRedWord)) {
            //只要把关键字变红就行了,不需要加点击事件。如果需要,可以自己加
            String temp = content;
            int startNew = 0;
            int startOld = 0;
            while (temp.contains(toRedWord)) {
                spannableString.setSpan(new ClickableSpan() {

                                            @Override
                                            public void updateDrawState(TextPaint ds) {
                                                // TODO Auto-generated method stub
                                                super.updateDrawState(ds);
                                                ds.setColor(0xffff0000);
                                                ds.setUnderlineText(false);
                                            }

                                            @Override
                                            public void onClick(View widget) {
                                            }

                                        }, startOld + temp.indexOf(toRedWord), startOld + temp.indexOf(toRedWord) + toRedWord.length(),
                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
                setText(spannableString);
                setMovementMethod(CustomLinkMovementMethod.getInstance());
                startNew = temp.indexOf(toRedWord) + toRedWord.length();
                startOld += startNew;
                temp = temp.substring(startNew);
            }
        } else {
            setText(spannableString);
        }


    }


    //-------------------------------------------------------------


    public boolean linkHit;//内部链接是否被点击

    @Override
    public boolean performClick() {
        if (linkHit) {
            return true;
        }
        return super.performClick();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        linkHit = false;
        return super.onTouchEvent(event);
    }

    public static class CustomLinkMovementMethod extends LinkMovementMethod {

        static CustomLinkMovementMethod 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 MyTextView_2) {
                        ((MyTextView_2) widget).linkHit = true;
                    }

                    return true;
                } else {
                    Selection.removeSelection(buffer);
                    super.onTouchEvent(widget, buffer, event);
                    return false;
                }
            }

            return Touch.onTouchEvent(widget, buffer, event);
        }

        public static CustomLinkMovementMethod getInstance() {
            if (sInstance == null) {
                sInstance = new CustomLinkMovementMethod();
            }
            return sInstance;
        }
    }


}

5、KeyBean

package com.chen.customviewdemo.bean;

/**
 * 关键字bean。
 * 包含显式内容和隐式内容。
 * 如:在界面上显示“百度”,点击了它,就去一个界面打开百度的网页。要打开网页,肯定需要Url。这就需要,在点击的时候,把Url传递过去。
 * 这个时候,这个Url,就是隐式内容了。不必让用户看到,只是在触发后,隐含的做一定操作就行
 */
public class KeyBean {

    public KeyBean(String content, String hide_content) {
        this.content = content;
        this.hide_content = hide_content;
    }

    /**
     * 内容
     */
    public String content;

    /**
     * 隐藏的内容,点击内容后,要传递的值或者要做的事
     */
    public String hide_content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getHide_content() {
        return hide_content;
    }

    public void setHide_content(String hide_content) {
        this.hide_content = hide_content;
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值