在Textview中获取指定文字位置(兼顾网址链接和emoji表情),并在其附近展示图片

本文介绍如何在Textview中获取指定文字位置,包括网址链接和emoji表情,并在关键字处展示图片。提供了单独展示和在ListView中的实现方法,以及文字宽高的测量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要讲在Textview中获取指定文字的位置,最后,附带一点文字宽高的测量。
下面,我会给出全部源码。自己建个demo,复制进去就能跑起来。

先强调一下,不建议在ListView中使用。最好是在一个单独展示Textview的界面中使用。

先上效果图:
这里写图片描述

需求及说明:给出一段文字,里面可能包含链接或表情。同时,也有要匹配的关键字,最后,在关键字处展示一个图片,用于强调这个关键字。对应关键字,也可能有多种情况,如:@人名、股票代码等。这里ABC和000001代替。最后,我要在第一个出现的000001位置展示图片。

在源码开始前,先看看项目结构:
这里写图片描述

说明:
CHEN是工具类
DataBean是listView中,list里面要放的数据的对象
KeyBean是关键字对象
Mainactivity_1是单纯展示一个Textview展示效果图中的内容
Mainactivity_2是把1中的功能放到ListView中(有问题,到现在为止,我没解决,下面会详细说)
Mainactivity_3是文字宽高的测量
MyTextView是可以匹配链接和表情的自定义Textview
PicImageView是自定义的ImageView,是用于自动展示帧动画的ImageView
ViewHolder是ListView中用的

代码:
先上工具相关的准备东西:
CHEN

package com.chen.demo;

import android.content.Context;

public class CHEN {
   
   

    /**
     * 网址要被替换成的文字
     */
    public static String REPLACEMENT_STRING = "*点击链接";

    //    /**
    //     * 匹配网址的正则表达式。以http://为例
    //     */
    //    public static String urlRegex = "(http://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|([a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)";

    /**
     * 匹配网址的正则表达式。有http://、https://、ftp://这3中开头的
     */
    public static String urlRegex = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)|([a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>,]*)?)";

    public static int sp2px(float spValue, Context context) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

}

DataBean

package com.chen.demo;

public class DataBean {

    //关键字的内容
    private String content;
    //类型,用于区分是否需要在关键字位置显示图片
    private String type;

    public String getContent() {
        return content;
    }

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

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

KeyBean

package com.chen.demo;


public class KeyBean {

    //关键字的内容
    private String content;

    public String getContent() {
        return content;
    }

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

}

ViewHolder

package com.chen.demo;

import android.util.SparseArray;
import android.view.View;


public class ViewHolder {
   
   

    private ViewHolder(){

    }


    public static <T extends View> T get(View convertView, int id){

        SparseArray<View> viewHolder=(SparseArray<View>) convertView.getTag();
        if(viewHolder==null){
            viewHolder=new SparseArray<View>();
            convertView.setTag(viewHolder);
        }
        View childView=viewHolder.get(id);
        if(childView==null){
            childView=convertView.findViewById(id);
            viewHolder.put(id, childView);
        }
        return (T)childView;
    }

}

自定义View
MyTextView
这里面定义了2种方法,一种是直接展示内容,关于关键字的位置,需要通过另外的方法获取;一种是展示完后直接返回关键字的位置

package com.chen.demo;


import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
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.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MyTextView extends TextView {

    private Context context = null;

    private int firstKeyWordPosition = -1;

    public MyTextView(Context context) {
        super(context);
        this.context = context;
    }

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

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


    public void showContent_1(String str, ArrayList<KeyBean> keyBeanList) {

        String content = str;

        //处理匹配的url
        Pattern p = Pattern.compile(CHEN.urlRegex);
        Matcher m = p.matcher(content);
        ArrayList<String> urlList = new ArrayList<String>();
        while (m.find()) {
            String urlStr = m.group();
            if (urlStr.contains("http://") || urlStr.contains("ftp://")) {
                //如果末尾有英文逗号或者中文逗号等,就去掉
                while (urlStr.endsWith(",") || urlStr.endsWith(",") || urlStr.endsWith(".") || urlStr.endsWith("。") || urlStr.endsWith(";") || urlStr.endsWith(";") || urlStr.endsWith("!") || urlStr.endsWith("!") || urlStr.endsWith("?") || urlStr.endsWith("?")) {
                    urlStr = urlStr.substring(0, urlStr.length() - 1);
                }
                urlList.add(urlStr);
                content = content.replace(urlStr, CHEN.REPLACEMENT_STRING);
            }
        }

        SpannableString spannableString = new SpannableString(content);

        //处理表情相关
        String emoji_string = "\\[(.+?)\\]";
        Pattern emoji_patten = Pattern.compile(emoji_string);
        Matcher matcher = emoji_patten.matcher(content);

        while (matcher.find()) {

            Drawable drawable = context.getResources().getDrawable(R.mipmap.emoji_weixiao);
            drawable.setBounds(0, 0, CHEN.sp2px(25, context), CHEN.sp2px(25, context));
            ImageSpan imgSpan = new ImageSpan(drawable);
            spannableString.setSpan(imgSpan, matcher.start(),
                    matcher.end(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        }

        //表情相关处理结束

        content = spannableString.toString();
        //处理链接
        if (urlList.size() > 0) {

            int urlStartNew = 0;
            int urlStartOld = 0;

            String urlTemp = content;

            for (int i = 0; i < urlList.size(); i++) {
   
   

                final String regexUrl = urlList.get(i);

                spannableString.setSpan(new ClickableSpan() {

                                            @Override
                                            public void updateDrawState(TextPaint ds) {
                                                // TODO Auto-generated method stub
                                                super.updateDrawState(ds);
                                                ds.setColor(0xff2097D9);
                                                ds.setUnderlineText(false);
                   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值