Android-TextView中关键字文字颜色区别于普通文字的实现

本文介绍了两种在Android中使TextView中关键字颜色区别的方法,重点讲解了使用SpannableStringBuilder配合setSpan()函数实现文字颜色变化。通过setSpan(),可以设置字符串的样式,例如颜色,且详细解释了不同Flag参数的含义。示例中展示了在搜索结果中高亮关键字的场景,同时也提出了全匹配和大小写匹配的问题及解决方案。
摘要由CSDN通过智能技术生成

总结了一下,一般有两种方法,下面来介绍一下。

一、使用html的方法Html.fromHtml(str):

这个方法很简单,我不详细写了,请参考文章:http://blog.csdn.net/youngmy5/article/details/50012229


二、使用SpannableStringBuilder:

这种方法比较复杂,但是学会了使用比第一种好用非常多,因为这个类的功能挺强大的,可字符串拼接、改变字体、改变颜色都不是问题,这里重点说改变颜色,我们需要使用到的方法是setSpan()函数

setSpan()函数介绍:截取自http://blog.csdn.net/jsjqcs/article/details/49149219

函数意义:给SpannableString或SpannableStringBuilder特定范围的字符串设定Span样式,可以设置多个(比如同时加上下划线和删除线等),Falg参数标识了当在所标记范围前和标记范围后紧贴着插入新字符时的动作,即是否对新插入的字符应用同样的样式。(这个后面会具体举例说明) 
参数说明 
object what :对应的各种Span,后面会提到; 
int start:开始应用指定Span的位置,索引从0开始 
int end:结束应用指定Span的位置,特效并不包括这个位置。比如如果这里数为3(即第4个字符),第4个字符不会有任何特效。从下面的例子也可以看出来。 
int flags:取值有如下四个 
1)、Spannable.SPAN_EXCLUSIVE_EXCLUSIVE:前后都不包括,即在指定范围的前面和后面插入新字符都不会应用新样式 
2)、Spannable.SPAN_EXCLUSIVE_INCLUSIVE :前面不包括,后面包括。即仅在范围字符的后面插入新字符时会应用新样式 
3)、Spannable.SPAN_INCLUSIVE_EXCLUSIVE :前面包括,后面不包括。 
4)、Spannable.SPAN_INCLUSIVE_INCLUSIVE :前后都包括。 
举个例子来说明这个前后包括的问题:如给定一串字符串为123456789,现在设置显示效果为将123456789中的34设置成红色字体,如果flags设置的是Spannable.SPAN_INCLUSIVE_INCLUSIVE这种前后都包括的话,那么你在字符串中123456789中34子字符串中前后添加字符的话都会直接设置成红色字体。 


下面看下具体如何使用这个方法,这里是我模拟的一个搜索页面,然后搜索的到结果的关键字将会标亮。

1.item布局页面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_item"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="20dp">


    <TextView
        android:id="@+id/tv_search_course_content"
        android:layout_width="match_parent"
        android:layout_height="35.0dp"
        android:paddingLeft="10.0dp"
        android:paddingRight="10.0dp"
        android:text="--"
        android:textColor="@color/word_color_666666"
        android:textSize="@dimen/text_size_s16"
        android:singleLine="true"
        android:ellipsize="end"
        android:gravity="center_vertical"/>
</LinearLayout>

2.我这里使用的是RecycleView,主页面布局不写了,就给个控件吧

<android.support.v7.widget.RecyclerView
                android:id="@+id/rv_search_result"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:overScrollMode="never">
            </android.support.v7.widget.RecyclerView>

3.布局写好了就要写适配器Adapter了

public class CourseSearchAdapter extends RecyclerView.Adapter{
    private List<DetailItemShowBean.CourseInfoBean> mCourseInfoBeenList = new ArrayList<>();
    private Listener mListener;
    private Context mContext;
    private String mSearchString;

    public CourseSearchAdapter(Context context, List<DetailItemShowBean.CourseInfoBean> courseInfoBeenList,String keyWord, Listener listener){
        mCourseInfoBeenList = courseInfoBeenList;
        mListener = listener;
        mContext = context;
        mSearchString = keyWord;
    }

    public void removeData () {
        notifyItemRangeRemoved (0, getItemCount());
        mCourseInfoBeenList.clear ();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return CourseHolder.newHolder(parent,mContext);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        CourseHolder courseHolder = (CourseHolder) holder;
        DetailItemShowBean.CourseInfoBean courseInfoBean = mCourseInfoBeenList.get(position);
        String courseName = courseInfoBean.getCourseName();
        courseHolder.mTextView.setText(getSpannableString(courseName));  //显示关键字的标亮方法
        courseHolder.mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.itemClickListener(courseInfoBean);
            }
        });
    }

    @Override
    public int getItemCount() {
        return mCourseInfoBeenList.size();
    }

    private static class CourseHolder extends RecyclerView.ViewHolder {
        TextView mTextView;

        public CourseHolder(Context context, View itemView) {
            super(itemView);
            mTextView = (TextView) itemView.findViewById(R.id.tv_search_course_content);
        }

        private static CourseHolder newHolder(ViewGroup parent, Context context) {
            View view = LayoutInflater.from(context).inflate(R.layout.list_item_search_course_content, parent, false);
            return new CourseHolder(context, view);
        }
    }
}

4.我们在适配器拿到要显示的内容后,调用前面介绍的方法去标亮关键字,注释在代码了,这里不解释了,mSearchString就是关键字。

   public SpannableStringBuilder getSpannableString(String str){

        //不包含关键字的时候
        if(!str.contains(mSearchString)){
            SpannableStringBuilder styleAll = new SpannableStringBuilder(str);
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),0,str.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            return styleAll;
        }
        //关键字和结果一样的时候
        if(str.equals(mSearchString)){
            SpannableStringBuilder styleAll = new SpannableStringBuilder(str);
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.main_color)),0,str.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            return styleAll;
        }
        //含有关键字且不等于关键字的时候
        int keyWordStart = str.indexOf(mSearchString);
        int keyWordEnd= keyWordStart + mSearchString.length();
        if(keyWordStart == 0 && keyWordEnd != str.length()){
            //关键字在开头
            int normalWordStart = keyWordEnd;
            int normalWordEnd = str.length();
            SpannableStringBuilder styleAll = new SpannableStringBuilder(str.substring(keyWordStart,keyWordEnd));
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.main_color)),keyWordStart,keyWordEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
//            style.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),normalWordStart,normalWordEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            String subString = str.substring(normalWordStart,normalWordEnd);  //关键字后面剩余的字符串长度
            if(subString.length() >= mSearchString.length()){
                //当关键字之后的字符长度大于关键字,再次循环,把余下的字符串再判断,然后拼接过来
                styleAll.append(getSpannableString(subString));
            }else {
                SpannableStringBuilder sub = new SpannableStringBuilder(subString);
                //否则直接赋予颜色值
                sub.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),0,sub.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                styleAll.append(sub);
            }
            return styleAll;
        }else if(keyWordEnd == str.length() && keyWordStart != 0){
            SpannableStringBuilder styleAll = new SpannableStringBuilder(str);   //在结尾的可以直接使用整个字符串
            //关键字在结尾
            int normalWordStart = 0;
            int normalWordEnd = keyWordStart;
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),normalWordStart,normalWordEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.main_color)),keyWordStart,keyWordEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            return styleAll;
        }else {
            SpannableStringBuilder styleAll = new SpannableStringBuilder(str.substring(0,keyWordEnd));
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.main_color)),keyWordStart,keyWordEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            //关键字在中间
            int normalWordStart1 = 0;
            int normalWordEnd1 = keyWordStart;
            int normalWordStart2 = keyWordEnd;
            int normalWordEnd2 = str.length();
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),normalWordStart1,normalWordEnd1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.main_color)),keyWordStart,keyWordEnd, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            String subString = str.substring(normalWordStart2,normalWordEnd2);  //关键字后面剩余的字符串长度
            if(subString.length() >= mSearchString.length()){
                //当关键字之后的字符长度大于关键字,再次循环,把余下的字符串再判断,然后拼接过来
                styleAll.append(getSpannableString(subString));
            }else {
                SpannableStringBuilder sub = new SpannableStringBuilder(subString);
                //否则直接赋予颜色值
                sub.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),0,sub.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                styleAll.append(sub);
            }
            return styleAll;
        }
    }

最后在主页把控件声明调用适配器就行了,关于RecycleView的使用这里不做介绍了,可以参考我以前的文章http://blog.csdn.net/nzzl54/article/details/52171354,效果图在评论中展示。


注意:最后再说个事,上面是全匹配的情况下才会标亮,如果你搜索的结果有大小写的话,就无法匹配,比如你搜索“Aa”,而结果有“”AA“、“aA”、"aa",这些将不会被标亮。

如果你想做到不区分大小写的匹配,我们可以这样做:

1.先把关键字和搜索出来的结果都进行大小写转换,把所有的大写都转成小写

//大写转小写
    public static String exChange(String str){
        StringBuffer sb = new StringBuffer();
        if(str!=null){
            for(int i=0;i<str.length();i++){
                char c = str.charAt(i);
                if(Character.isUpperCase(c)){
                    sb.append(Character.toLowerCase(c));
                }else{
                    sb.append(c);
                }
            }
        }
        return sb.toString();
    }

2.在使用上面给的标亮函数中,我们也要做一些修改:这里只粘贴出修改部分,请看注释。

String allLowerCaseStr = exChange(string);  //结果转成全小写
        String mSearchStr = exChange(this.mSearchString);  //搜索关键字转为全小写
        //不包含关键字的时候,注意这里是用上面的那两个全小写String作为比较
        if(!allLowerCaseStr.contains(mSearchStr)){
            SpannableStringBuilder styleAll = new SpannableStringBuilder(string);
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.word_color_666666)),0,string.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            return styleAll;
        }
        //关键字和结果一样的时候,注意这里是用上面的那两个全小写String作为比较
        if(allLowerCaseStr.equals(mSearchStr)){
            SpannableStringBuilder styleAll = new SpannableStringBuilder(string);
            styleAll.setSpan(new ForegroundColorSpan(mContext.getResources().getColor(R.color.main_color)),0,string.length(), Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
            return styleAll;
        }
        //含有关键字且不等于关键字的时候,这里也是用全小写拿到关键字的位置
        int keyWordStart = allLowerCaseStr.indexOf(mSearchStr);
        int keyWordEnd= keyWordStart + mSearchStr.length();
这样就可以进行不区分大小写的标亮啦,效果图请看第二个评论。


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值