Android - 在 TextView 中突出显示一个单词?

Posted

技术标签:

【中文标题】Android - 在 TextView 中突出显示一个单词?【英文标题】:Android - Highlight a Word In a TextView? 【发布时间】:2011-10-14 04:32:27 【问题描述】:

我有一个database search query,它在数据库中搜索用户输入的单词并返回Cursor

在我的ListActivity 中,我有一个ListView,它将保存项目(光标项目)。 ListView 项目布局基本上是 TextView。我的意思是,ListView 将是TextView 的列表。

我想要的是突出显示 search term 出现在 TextView 中的任何位置。我的意思是突出显示:不同的颜色或不同的背景颜色或任何使它与文本的其余部分不同的东西。

这可能吗?以及如何?

更新:

cursor = myDbHelper.search(term);  //term: a word entered by the user.
cursor.moveToFirst();
String[] columns = cursor.getColumnName(1); 
int[] columnsLayouts = R.id.item_title; //item_title: the TextView holding the one raw
ca = new SimpleCursorAdapter(this.getBaseContext(), R.layout.items_layout, cursor,columns , columnsLayouts);
lv = getListView();
lv.setAdapter(ca);

对于@Shailendra:search() 方法将返回一些标题。我想突出显示与term 单词匹配的标题中的单词。我希望这现在很清楚了。

【问题讨论】:

【参考方案1】:

为 word 周围的颜色插入 html 代码并将其设置为您的 textView 。

喜欢

String newString = oldString.replaceAll(textToHighlight, "<font color='red'>"+textToHighlight+"</font>");
textView.setText(Html.fromHtml(newString));

【讨论】:

问题是它不是一个简单的 TextView 来保存文本。它是一个保存查询结果的 ListView(可能是 1 个或多个结果。因此,可能是一个 TextView 或更多)。所以,我怀疑我可以通过这种方式更改此列表中的文本,可以吗? 所以??我在 listview 中看不到任何关于文本的问题......你能详细说明你的问题吗??? 这里您使用的是 SimpleCursorAdapter,它将各自列的 Text 设置为 TextView R.id.item_title 。所以制作将扩展 SimpleCursorAdapter 的 customAdapter 。将 String term 传递给它并将上面的 replaceAll 代码写入 getView 覆盖方法 我会试试然后回到这里:) 如果用户输入html标签,他们不能对文本做一些有趣的事情吗?【参考方案2】:
TextView textView = (TextView)findViewById(R.id.mytextview01);

//use a loop to change text color
Spannable WordtoSpan = new SpannableString("partial colored text");        
WordtoSpan.setSpan(new ForegroundColorSpan(Color.BLUE), 2, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
textView.setText(WordtoSpan);

数字 2 和 4 是文本着色的开始/停止索引,在本例中,“rti”将被着色。

所以你基本上只会在标题中找到搜索词的起始索引:

int startIndex = titleText.indexOf(term);
int stopIndex = startIndex + term.length();

然后用索引替换数字 2 和 4,用标题字符串替换“部分彩色文本”。

来源:https://***.com/a/10279703/2160827

【讨论】:

【参考方案3】:

更简单的方法

您可以使用Spannable 类来突出显示/格式化文本的一部分。

textView.setText("Hello, I am Awesome, Most Awesome"); // set text first
setHighLightedText(textView, "a"); // highlight all `a` in TextView

方法如下。

 /**
     * use this method to highlight a text in TextView
     *
     * @param tv              TextView or Edittext or Button (or derived from TextView)
     * @param textToHighlight Text to highlight
     */
    public void setHighLightedText(TextView tv, String textToHighlight) 
        String tvt = tv.getText().toString();
        int ofe = tvt.indexOf(textToHighlight, 0);
        Spannable wordToSpan = new SpannableString(tv.getText());
        for (int ofs = 0; ofs < tvt.length() && ofe != -1; ofs = ofe + 1) 
            ofe = tvt.indexOf(textToHighlight, ofs);
            if (ofe == -1)
                break;
            else 
                // set color here
                wordToSpan.setSpan(new BackgroundColorSpan(0xFFFFFF00), ofe, ofe + textToHighlight.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                tv.setText(wordToSpan, TextView.BufferType.SPANNABLE);
            
        
    

您可以check this answer 获取可点击的高亮文本。

【讨论】:

非常简单。谢谢。【参考方案4】:

我知道这是个老问题,但我创建了一种方法来突出显示字符串\段落中的重复单词。

private Spannable highlight(int color, Spannable original, String word) 
    String normalized = Normalizer.normalize(original, Normalizer.Form.NFD)
            .replaceAll("\\pInCombiningDiacriticalMarks+", "");

    int start = normalized.indexOf(word);
    if (start < 0) 
        return original;
     else 
        Spannable highlighted = new SpannableString(original);
        while (start >= 0) 
            int spanStart = Math.min(start, original.length());
            int spanEnd = Math.min(start+word.length(), original.length());

            highlighted.setSpan(new ForegroundColorSpan(color), spanStart,
                    spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);

            start = normalizedText.indexOf(word, spanEnd);
        
        return highlighted;
    

用法:

textView.setText(highlight(primaryColor, textAll, wordToHighlight));

【讨论】:

如果我应该添加这个,不要将跨越的单词转换为字符串,否则它会失去所有的亮点【参考方案5】:

根据之前的回答我开发了以下功能,你可以复制/粘贴

 private void highlightMask(TextView textView, String text, String mask) 
            boolean highlightenabled = true;
            boolean isHighlighted = false;

            if (highlightenabled) 
                if (!TextUtils.isEmpty(text) && !TextUtils.isEmpty(mask)) 
                    String textLC = text.toLowerCase();
                    mask = mask.toLowerCase();

                    if (textLC.contains(mask)) 
                        int ofe = textLC.indexOf(mask, 0);
                        Spannable wordToSpan = new SpannableString(text);
                        for (int ofs = 0; ofs < textLC.length() && ofe != -1; ofs = ofe + 1) 
                            ofe = textLC.indexOf(mask, ofs);
                            if (ofe == -1) 
                                break;
                             else 
                                // set color here
                                wordToSpan.setSpan(new BackgroundColorSpan(0xFFFFFF00), ofe, ofe + mask.length(),
                                                   Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                                textView.setText(wordToSpan, TextView.BufferType.SPANNABLE);
                                isHighlighted = true;
                            
                        

                    
                
            

            if (!isHighlighted) 
                textView.setText(text);
            
        

【讨论】:

【参考方案6】:

我还没有这样做,但这看起来很有希望:

http://developer.android.com/reference/android/text/SpannableString.html
http://developer.android.com/guide/topics/resources/string-resource.html

public final void setText(字符序列文本)

自:API 级别 1 设置 TextView 的字符串值。文本视图 不接受类似 HTML 的格式,您可以对文本执行此操作 XML 资源文件中的字符串。要设置您的琴弦样式,请附上 android.text.style.* 对象到 SpannableString,或查看 设置示例的可用资源类型文档 XML 资源文件中的格式化文本。

http://developer.android.com/reference/android/widget/TextView.html

【讨论】:

【参考方案7】:

试试这个库Android TextHighlighter。

实现

TextView.setText() 获得一个参数为Spannable,而不仅仅是CharacterSequence。 SpannableString 有一个方法setSpan() 允许应用样式。

查看直接子类列表 CharacterStyle https://developer.android.com/reference/android/text/style/CharacterStyle.html

为“Hello, World”中的单词“Hello”赋予背景色和前景色的示例
Spannable spannable = new SpannableString("Hello, World");
// setting red foreground color
ForegroundSpan fgSpan = new ForegroundColorSpan(Color.red);
// setting blue background color
BackgroundSpan bgSpan = new BackgroundColorSPan(Color.blue);

// setSpan requires start and end index
// in our case, it's 0 and 5
// You can directly set fgSpan or bgSpan, however,
// to reuse defined CharacterStyle, use CharacterStyle.wrap()
spannable.setSpan(CharacterStyle.wrap(fgSpan), 0, 5, 0);
spannable.setSpan(CharacterStyle.wrap(bgSpan), 0, 5, 0);

// apply spannableString on textview
textView.setText(spannable);

【讨论】:

要使用该库,请添加到 gradle:compile 'com.xeoh.android:text-highlighter:1.0.1'(但您的示例代码不适用于该库)【参考方案8】:

如果您的字符串是静态的,您可以在 xml strings 中这样做

<string name="my_text">This text is <font color='red'>red here</font></string>

【讨论】:

【参考方案9】:

我知道这个线程是旧的,但以防万一有人想在 textview 中突出显示字符串,我创建了一个库来执行此操作。这是我刚刚加入的关于堆栈溢出的问题的第一个答案,希望它的格式正确且相关。它使用 SpannableString 并将定位您指定的字符串的所有出现。此外,内置的自定义 ClickableSpan 让您可以选择为单击的文本设置侦听器(如果需要)。

链接器

轻量级的 android 库,用于在 textview 中突出显示字符串(忽略大小写),带有可选的回调。

语言:Java

MinSDK:17

可以找到它的功能图片和所有代码 here.

JavaDocs

将工件引入您的 android 项目:

在项目级别的 build.gradle 中

    allprojects 
        repositories 
            ...
            maven  url 'https://jitpack.io' 
        
    

在 App 级别的 build.gradle 中

       dependencies 
            implementation 'com.github.Gaineyj0349:Linker:1.2'
    

使用方法:

1 - 使用 textview 构造一个 Linker 对象:

        Linker linker = new Linker(textView);

2 - 添加要在 textview 文本中突出显示的数组或字符串列表:

        ArrayList<String> list = new ArrayList<>();
        list.add("hello");
        list.add("world");
        linker.addStrings(list);

与/或

        String[] words = new String[]"One", "Two", "Three";
        linker.addStrings(words);

3 - 添加回调:(这是可选的):

       linker.setListener(new LinkerListener() 
            @Override
            public void onLinkClick(String charSequenceClicked) 

                // charSequenceClicked is the word that was clicked

                Toast.makeText(MainActivity.this, charSequenceClicked, Toast.LENGTH_SHORT).show();
            
        );

4 - 调用链接器的更新方法以提交自定义并推出设置。:

        linker.update();

您始终可以选择将字符串添加到链接器对象,只需确保在刷新跨度后调用更新方法即可。

    linker.addStrings("yoda");
    linker.update();

如果您需要具有相同链接器对象的新石板,只需调用

       linker.clearLinksList()

您也可以自定义链接:

1 - 自定义所有链接颜色:

      linker.setAllLinkColors(Color.BLUE);

2 - 自定义链接下划线:

      linker.setAllLinkUnderline(false);

3 - 如果您希望为某个字符串自定义颜色或下划线设置(注意该字符串必须已经添加到链接器中):

      linker.setLinkColorForCharSequence("world", Color.MAGENTA);
      linker.setUnderlineModeForCharSequence("world", true);

4 - 如果您希望对每个单词使用不同的设置,那么您还可以为链接器对象提供一个 LinkProfile 列表或数组:

        ArrayList<LinkProfile> profiles = new ArrayList<>();
        profiles.add(new LinkProfile("hello world",
                Color.GREEN, false));
        profiles.add(new LinkProfile("goodbye cruel world",
                Color.RED, false));
        profiles.add(new LinkProfile("Whoa awesome!",
                Color.CYAN, true));


        linker.addProfiles(profiles);

记得在对链接器对象添加任何内容后调用 .update()。

请注意,库会处理一些细微的问题,例如添加两个相同的单词或单词的相同部分。例如,如果“helloworld”和“hello”是添加到链接器中的两个词,当它们在相同的字符范围内时,“helloworld”将优先于“hello”。链接器将首先根据较大的单词进行排序,并在链接它们时跟踪所有跨度 - 避免重复和相交跨度的问题。

在 MIT 许可下获得许可。

【讨论】:

以上是关于Android - 在 TextView 中突出显示一个单词?的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式单击时突出显示 TextView

CardView 中突出显示的文本没有颜色

为 textview 设置选定状态(突出显示)

如何突出显示 ListView-Items

Android:长按时突出显示段落中的句子

如何在单击 TextView 时像单击按钮一样突出显示它