Android Textview prend en charge le clic partiel, ClickableSpan (texte enrichi) et résout les conflits de glissement LinkMovementMethod

TextView contient des liens partiellement cliquables, et il existe des événements de clic correspondants dans d'autres parties du lien. Le format est défini dans le texte, public void setSpan (Object what, int start, int end, int flags) {} Cliquez pour savoir où Which les mots dans le texte doivent être cliqués.

Exemples 格式:Bonjour Android <b>Cliquez sur Détail # https://www.baidu.com</b>

Exigences :
(1) <b> --- # Affichage : Police cliquable en bleu.
(2) # --- </b> Ne pas afficher : URL cliquable en police bleue.
(3) La police par défaut est noire.

1. Selon le processus, obtenez d'abord le texte de <b> à </b>, interceptez-le et collez-le dans le texte original. L'URL utilise setSpan (nouveau ClickableSpan()) pour définir le saut de l'événement de clic. Certains les experts l'ont dit, substring(

) Il est si facile d'intercepter les clics via ClickableSpan que vous ne pouvez pas le dire, jetez un œil ci-dessous :

Si le format des exemples n'est pas fixe :<b>ClickableSpan nous permet de répondre aux événements de clic lorsque nous cliquez sur le texte correspondant de TextView# https://www.baidu.com </b>, tel que l'URLSpan couramment utilisé, ouvrira le lien correspondant lorsque vous cliquerez dessus. Pour que TextView réponde aux clics ClickableSpan, <b>nous devons définir LinkMovementMethod pour cela, # https://www.baidu.com</b> Mais ceci\n\n" <b>LinkMovementMethod a beaucoup de Pit# https://www.csdn.net</b> <b>LinkMovementMethod a un autre gros gouffre# https://www.baidu.com</b>Comment le résoudre ? Il y en a beaucoup, setMovementMethod(LinkMovementMethod .getInstance()) glissement, espace, nouvelle ligne.

Le rendu:


//Définissez le lien hypertexte dans TextView pour qu'il soit cliquable spannableTextView.setMovementMethod(LinkMovementMethod.getInstance());
*Prise en charge de Textview pour définir des clics de texte enrichi
*Définissez le paramètre de texte du milieu dans Textview pour qu'il soit cliquable et changez de couleur,
*Définissez setMovementMethod(LinkMovementMethod. getInstance()) Il y a un conflit entre le clic et le glissement de Textview.
* Résoudre le problème du clic sur la zone vide et du fait d'avoir toujours des événements de clic.

//1. 截取并设置点击 Help class
public class MyDataHelp {
    public static final String TAG = MyDataHelp.class.getSimpleName();
    private static String start_label = "<b>", sub_label = "#", end_label = "</b>", http = "http";//设置截取的格式

    //处理数据
    public static void dealWithContent(String with_content, final CallBack callBack) {
        Log.i(TAG, "获取到的content: " + with_content);
        try {
            final ArrayList<String> list = new ArrayList<>();
            //按照</b>截取,看看有几个可以点击需要进行数据处理
            String[] split = with_content.split(end_label);
            for (String split_content : split) {
                if (split_content.contains(start_label) && split_content.contains(sub_label)) {
                    String substring = split_content.substring(split_content.indexOf(start_label), split_content.length());
                    Log.i(TAG, "substring : " + substring);
                    list.add(substring);
                }
            }
            ArrayList<String> list_title = new ArrayList<>(); //截取<b> --- # 显示的文字 list
            final ArrayList<String> list_url = new ArrayList<>(); //截取<b> --- # URL
            for (int i = 0; i < list.size(); i++) {
                if (with_content.contains(list.get(i))) {
                    String list_content = list.get(i);
                    String sub_title = list_content.substring(list_content.indexOf(start_label) + 3, list_content.indexOf(sub_label));
                    final String url;
                    if (list_content.contains(http)) {
                        url = list_content.substring(list_content.indexOf(http), list_content.length());
                    } else {
                        url = list_content.substring(list_content.indexOf(sub_label) + 2, list_content.length());
                    }
                    String start = with_content.substring(0, with_content.indexOf(start_label));
                    String end = with_content.substring(with_content.indexOf(end_label) + 4, with_content.length());
                    String all_text = start + sub_title + end;
                    with_content = all_text;
                    Log.i(TAG, "all_text : " + all_text);
                    list_title.add(sub_title);
                    list_url.add(url);
                    Log.i(TAG, "sub_title : " + sub_title + " url: " + url);
                }
            }
            SpannableStringBuilder ssb = new SpannableStringBuilder(with_content);//进行拼接和设置点击事件
            int indexOf = 0;
            for (int i = 0; i < list_title.size(); i++) {
                String list_text = list_title.get(i);
                list_text.replaceAll(" ", "");//替换中间的空格
                final String URL = list_url.get(i);
                Log.i(TAG, "list_text : " + list_text + " URL: " + URL);
                //为了解决重复<b>Click Detail # https://www.baidu.com</b> 好多相同的indexOf默认只取第一个,接着往下遍历.
                indexOf = with_content.indexOf(list_text, i == 0 ? 0 : indexOf + list_text.length());
                if (indexOf == -1) {//找不到会返回-1,只好再重新查找
                    indexOf = with_content.indexOf(list_text);
                }
                //设置点击文字的click和颜色
                ssb.setSpan(new ForegroundColorSpan(Color.parseColor("#2497df")), indexOf, indexOf + list_text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
                ssb.setSpan(new ClickableSpan() {
                    @Override
                    public void onClick(@NonNull View view) {
                        Log.i(TAG, "click url: " + URL);
                        callBack.dealUrl(URL);
                    }

                    @Override
                    public void updateDrawState(@NonNull TextPaint ds) {
                        ds.setUnderlineText(false);    //去除超链接的下划线
                    }
                }, indexOf, indexOf + list_text.length() - 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); //list_text.length() - 1为了解决点击空白区域依然有点击事件
                Log.i(TAG, "ssb : " + ssb);
            }
            callBack.dealText(ssb);
        } catch (Exception e) {
            Log.i(TAG, "e.getMessage(): " + e.getMessage());//必要时走try
        }
    }

    public interface CallBack {
        void dealText(SpannableStringBuilder text);

        void dealUrl(String URL);
    }

}
// 2. 解决布局clcik与TextView本身滑动冲突
public class MyTextView extends TextView {
    private static String TAG = "MyTextView";

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

    public MyTextView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public boolean linkHit;//内部富文本是否被点击
    private static long lastClickTime;

    private static final long CLICK_DELAY = 500l;


    @Override
    public boolean performClick() {   //最后响应3
        if (linkHit) {
            return true;    //这样textView的OnClick事件不会响应
        }
        return super.performClick();  //调用监听的onClick方法
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {   //textView的OnClick事件响应,首先响应1
        linkHit = false;
        return super.onTouchEvent(event);
    }

    public static class CustomLinkMovementMethod extends LinkMovementMethod { //次之2

        static CustomLinkMovementMethod sInstance;
        //手指按下的点为(x1, y1)手指离开屏幕的点为(x2, y2)
        float x1 = 0;
        float x2 = 0;
        float y1 = 0;
        float y2 = 0;

        @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);
                //解决拦截滑动时触发Textview link 点击事件
                if (action == MotionEvent.ACTION_UP) {
                    //当手指离开的时候
                    x2 = event.getX();
                    y2 = event.getY();
                    if (y1 - y2 > 50) {
                        Log.i(TAG, "向上滑");
                        link = new ClickableSpan[0];
                    } else if (y2 - y1 > 50) {
                        Log.i(TAG, "向下滑");
                        link = new ClickableSpan[0];
                    }
                } else {
                    //当手指按下的时候
                    x1 = event.getX();
                    y1 = event.getY();
                }
                //不是滑动、link.length != 0,拦截处理 Textview link 点击事件 ,证明点击了
                if (link.length != 0) {
                    if (action == MotionEvent.ACTION_UP) {
                        Selection.setSelection(buffer,
                                buffer.getSpanStart(link[0]),
                                buffer.getSpanEnd(link[0]));
                        link[0].onClick(widget);
                        return true;
                    }
                } else {
                    Selection.removeSelection(buffer);
                }

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

        public static CustomLinkMovementMethod getInstance() {
            if (sInstance == null) {
                sInstance = new CustomLinkMovementMethod();
            }
            return sInstance;
        }
    }
}
// 3. Textview 赋值  
MyDataHelp.dealWithContent(content, new MyDataHelp.CallBack() {//处理富文本格式数据
            @Override
            public void dealText(SpannableStringBuilder ssb) {
                tv_content.setText(ssb);
                tv_content.setMovementMethod(MyTextView.CustomLinkMovementMethod.getInstance());//解决点击事件与Textview本身滑动冲突
                tv_content.setHighlightColor(ContextCompat.getColor(getContext(), R.color.white));//去掉点击后的背景颜色为透明
            }

            @Override
            public void dealUrl(String URL) {
                clickListenerInterface.doLink(URL);
            }
        });

  Si vous avez d'autres solutions, merci de m'indiquer

 l'adresse de téléchargement de la Démo.

Je suppose que tu aimes

Origine blog.csdn.net/zyy_give/article/details/105576800
conseillé
Classement