Android Spannable:如何清除颜色?

2024-01-05

我在 RecyclerView CardViews 的 SearchView 上设置了 Spannable。如果在 CardView 上找到用户输入的文本,则该文本将以红色突出显示。当 SearchView 行被清除时,我希望 CardView 文本返回到默认的黑色。目前,文本已被清除,并且颜色错误地保持为红色。我尝试在 TextView 上使用“removeSpan”,但没有成功。 TextView 是“cardBlankText2”。我在这里缺少什么?

RecyclerView Adapter file

private List<ListItem> mListItems;
...    

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_contact_item, parent,false);

    final ItemHolder itemHolder = new ItemHolder(view);    

    return itemHolder;
}

private static class ItemHolder extends RecyclerView.ViewHolder {

    private ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);

    private TextView cardBlankText2; 

    private ItemHolder(View itemView) {
        super(itemView);

        cardBlankText2 = (TextView) itemView.findViewById(R.id.cardBlankText2);
}

    public ForegroundColorSpan getForegroundColorSpan(){
        return foregroundColorSpan;
    }
} 


public void setFilter(List<ListItem> listItems, String searchString) {
    // Note: the String is to get s.toString() from the Main Activity SearchView.
    // Note the plural for listItems.
    mListItems = new ArrayList<>();
    mListItems.addAll(listItems);
    this.searchString = searchString;
    notifyDataSetChanged();
}

public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {

    final ListItem listItem = mListItems.get(position);


    String todoHighlight = listItem.getTodo().toLowerCase(Locale.getDefault());
    String note1Highlight = listItem.getNote1().toLowerCase(Locale.getDefault());

    // Set up the logic for the highlighted text
    int todoStartPos = todoHighlight.indexOf(searchString);
    int todoEndPos = todoStartPos + searchString.length();
    int note1StartPos = note1Highlight.indexOf(searchString);
    int note1EndPos = note1StartPos + searchString.length();
    Spannable spanString2 = Spannable.Factory.getInstance().newSpannable(
            itemHolder.cardBlankText2.getText());        

    if (todoStartPos != -1 && searchString.length() > 0 && todoHighlight.contains(searchString)) {
        spanString2.setSpan(new ForegroundColorSpan(Color.RED), todoStartPos, todoEndPos,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        itemHolder.cardBlankText2.setText(spanString2);
    }
    **else if (searchString.length() == 0) {
        spanString2.removeSpan(itemHolder.cardBlankText2.getText());
        itemHolder.cardBlankText2.setText(spanString2);
    }**
}


MainActivity

public class MainActivity extends AppCompatActivity {

...
@Override
public boolean onCreateOptionsMenu(Menu menu) {

    getMenuInflater().inflate(R.menu.cardview_menu, menu);

    final MenuItem searchItem = menu.findItem(R.id.action_search);

    searchItem.setVisible(true);

    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);

    final SearchView mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem);mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
    final EditText mSearchEditText = (EditText) mSearchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);

        mSearchEditText.addTextChangedListener(new TextWatcher() {

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {                
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {                    
            }

            @Override
            public void afterTextChanged(Editable s) {


                final ArrayList<ListItem> filteredModelList2 = filter(allList, s.toString());

                if (!mSearchView.isIconified() && filteredModelList2.size() == 0) {

                        // re-load the list so the Adapter refreshes the RecyclerView list View.
                        adapter.clear();
                        adapter.addAll(allList);
                } else if (!mSearchView.isIconified() && filteredModelList2.size() > 0) {                            
                        adapter.setFilter(filteredModelList2, s.toString());
                        mRecyclerView.scrollToPosition(0);
                }
        });
        return super.onCreateOptionsMenu(menu);
    }  

// Do Search filtering from MainActivity's OnQueryTextChange(String newText)
// The Spannable code is in the onBindVH section for the itemHolders.
public ArrayList<ListItem> filter(List<ListItem> listItems, String query) {

    query = query.toLowerCase();

    final ArrayList<ListItem> filteredModelList = new ArrayList<>();
    for (ListItem listItem : listItems) {
        final String text = listItem.getTodo().toLowerCase();
        final String text2 = listItem.getNote1().toLowerCase();
        final String text3 = listItem.getNote2().toLowerCase();
        if (text.contains(query) || text2.contains(query) ||
            text3.contains(query)) {
            filteredModelList.add(listItem);
        }
    }
    return filteredModelList;
}

方法removeSpan()意味着是相反的操作setSpan(),所以你应该向它们传递相同的对象。为了实现这一目标,请使ForegroundColorSpan的一个领域ViewHolder(见下文)

public void onBindViewHolder(final MyViewHolder itemHolder, int position) {
    String todoHighlight = mListItems.get(position).getTodo();
    itemHolder.cardBlankText2.setText(todoHighlight);

    // Set up the logic for the highlighted text
    int todoStartPos = todoHighlight.indexOf(searchString);
    int todoEndPos = todoStartPos + searchString.length();

    // ... skipped some lines ...

    Spannable spanString2 = Spannable.Factory.getInstance().newSpannable(
        itemHolder.cardBlankText2.getText());        

    if (todoStartPos != -1 && searchString.length() > 0 && todoHighlight.contains(searchString)) {
        spanString2.setSpan(itemHolder.getForegroundColorSpan(), todoStartPos, todoEndPos,
            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        itemHolder.cardBlankText2.setText(spanString2);
    }
    else if (searchString.length() == 0) {
            spanString2.removeSpan(itemHolder.getForegroundColorSpan());
            itemHolder.cardBlankText2.setText(spanString2);
    }
}

视图持有者:

class MyViewHolder extends RecyclerView.ViewHolder{
    private ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.RED);

    public MyViewHolder(View itemView){
        super(itemView);
    }

    public ForegroundColorSpan getForegroundColorSpan(){
        return foregroundColorSpan;
    }
}

EDIT远程调试很困难,所以让我们以另一种方式进行,MCVE 风格:请使用以下代码,运行它,如果它有效(例如“根据搜索文本突出显示更改”),那么您就更进一步了道路。

public class Activity8_RecyclerViewGrid extends AppCompatActivity
{
    private int counter = 0;
    private static String[] searchTexts = new String[]{"rem", "ia", "", "ol" };

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity8__recycler_view);

        RecyclerView rcv = (RecyclerView)findViewById(R.id.recyclerView);
        rcv.setLayoutManager(new GridLayoutManager(this, 2));
        final MyAdapter adapter = new MyAdapter(allMyWords());
        rcv.setAdapter(adapter);

        final TextView tvSearchText = (TextView)findViewById(R.id.tvSearchText);

        Button btnFilter = (Button)findViewById(R.id.btnFilter);
        btnFilter.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View view)
            {
                String searchString = searchTexts[counter%4];
                adapter.setFilter(Activity7_GridViewStuff.allMyBooks(), searchString);
                tvSearchText.setText(searchString);
                counter++;
            }
        });
    }


    public static ArrayList<String> allMyWords()
    {
        String[] theLoremArray = null;
        String LOREM_STRING = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.";
        String[] sTemp = LOREM_STRING.split(" ");
        StringBuilder sb = new StringBuilder();

        theLoremArray = new String[sTemp.length/3];
        for (int i = 0; i < (sTemp.length - sTemp.length%3); i++)
        {
        sb.append(sTemp[i]).append(" ");
        if (i%3 == 2)
        {
            theLoremArray[i/3] = sb.toString();
            //  Log.d(TAG, "mLoremArray [" + i / 3 + "] = " + sb.toString());
            sb.delete(0, sb.length());
        }
    }

    ArrayList<String> words = new ArrayList<>();

    for (int i = 0; i < theLoremArray.length; i++)
        {
            words.add( theLoremArray[i]);
        }
        return words;
    }

    class MyAdapter extends RecyclerView.Adapter<MyHolder>{

        private List<String> data;
        private String searchString = "";

        MyAdapter(List<String> data){
            this.data = data;
        }

        public void setFilter(List<String> listItems, String searchString){
          //  data = new ArrayList<>();
          //  data.addAll(listItems);
            this.searchString = searchString;
            notifyDataSetChanged();
        }

        @Override
        public MyHolder onCreateViewHolder(ViewGroup parent, int viewType)
        {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity8_grid_cell, null);
            return new MyHolder(v);
        }

        @Override
        public void onBindViewHolder(final MyHolder holder, int position)
        {
            holder.text.setText(data.get(position));
            String todoHighlight = data.get(position);

            // Set up the logic for the highlighted text
            int todoStartPos = todoHighlight.indexOf(searchString);
            int todoEndPos = todoStartPos + searchString.length();

            Spannable spanString2 = Spannable.Factory.getInstance().newSpannable(holder.text.getText());

            if(todoStartPos != -1 && searchString.length() > 0 && todoHighlight.contains(searchString)){
                spanString2.setSpan(holder.getForegroundColorSpan(),    todoStartPos, todoEndPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
            else if (searchString.length() == 0){
                spanString2.removeSpan(holder.getForegroundColorSpan());
            }

            holder.text.setText(spanString2);
        }

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

    class MyHolder extends RecyclerView.ViewHolder{

        private ForegroundColorSpan foregroundColorSpan = new   ForegroundColorSpan(Color.CYAN);
        TextView text;

        public MyHolder(View itemView){
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.lorem_text);
        }

        public ForegroundColorSpan getForegroundColorSpan(){
            return foregroundColorSpan;
        }
    }
}

Activity8_recycler_view.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.samples.Activity8_RecyclerViewGrid">

    <TextView
        android:id="@+id/tvSearchText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:textAppearance="@style/Base.TextAppearance.AppCompat.Title"
        android:textColor="#ff0000" />

    <Button android:id="@+id/btnFilter"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="SET NEW FILTER"
        android:layout_gravity="center_horizontal" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="80dp">

    </android.support.v7.widget.RecyclerView>
</FrameLayout>

Activity8_grid_cell.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent">
    <TextView
        android:id="@+id/lorem_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:textAppearance="?android:attr/textAppearanceLarge" />
</FrameLayout>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Spannable:如何清除颜色? 的相关文章

  • Android 中的列表视图到 pdf

    我有一个自定义列表视图 我想从整个列表视图制作pdf 我参考了很多帖子并实现了下面的代码 该代码将我的列表视图转pdf 但问题是它不包含整个列表视图项目 pdf 中仅提供前几项 我的转换函数列表视图转pdf is fab setOnClic
  • 读取 Android 4.2 中的 APN?

    我有个问题阅读 APN在安卓v4 2中 是读 不是写APNS 它抛出一个安全异常 没有写入 APN 设置的权限 用户 10068 和当前用户都没有权限 进程有 android permission WRITE APN SETTINGS 相同
  • Android 服务 START_STICKY START_NOT_STICKY

    我需要让我的服务始终在后台运行 并使用 startService 函数启动我的服务 无论应用程序的状态如何 我都不想重新启动服务 这是我的观察 START STICKY gt 如果应用程序启动 则服务正在重新启动 当应用程序关闭时 服务也会
  • 垂直翻转 Android Canvas

    有没有一种简单的方法可以在 Android 中翻转画布 我似乎找不到任何可以让我垂直翻转它的东西 这样 y 轴上的零就是手机屏幕的底部而不是顶部 如果解决方案不是特别快也没关系 因为我没有对画布进行任何计算密集的操作 提前致谢 Try ca
  • Android:NotificationCompat.MediaStyle 操作按钮不执行任何操作

    我有一个简单的 Android 应用程序 其中包含一个Activity and a Service源自于MediaBrowserServiceCompat 我已成功将其设置为通过使用播放我的主要活动中的音频MediaBrowserCompa
  • Android 上 Java 库中的代码出现 NoClassDefFoundError

    我的用户经常遇到错误 应用程序在启动期间崩溃 当应该加载 MainActivity 时 VM 显然找不到该类 我不明白为什么 该应用程序的架构是 我的免费版和专业版都使用一个通用项目 不知道是否相关 请参阅下面的堆栈跟踪 有什么想法吗 ja
  • 如何修复运行 Android 模拟器时出现 GPU Driver Issue 错误

    我的 Android 模拟器几周前运行良好 但现在出现错误 当我运行代码时 GPU 驱动程序问题错误对话框与模拟器一起弹出 当我单击 确定 时 Android 模拟器不会按预期运行应用程序 错误如下 Your GPU driver info
  • 如何编写 adb jdwp + adbforward 脚本?

    我正在尝试使用命令行和脚本工具调试 Android 应用程序 我已经受够了 Android Studio 占用我的 CPU 要连接到我的应用程序 我需要adb jdwp获取 pid 然后adb forward tcp 8700 jdwp
  • 具有多个字符串的列表视图

    我正在尝试创建一个包含多个字符串的列表视图 现在我有一个可以实现的功能 while i lt 10 GETS DATA FROM WEBPAGE ETC a DATAFROMWEBPAGE1 b DATAFROMWEBPAGE2 c DAT
  • Android TabLayout:均匀分布

    我正在查看 Google IO 中使用的 Google 类 称为 SlidingTabLayout 在该类中 有一个名为 setDistributeEvenly 的方法 它允许所有这些选项卡在屏幕上均匀分布 每个选项卡具有相同的大小 中心对
  • 错误:类 kotlin.reflect.jvm.internal.FunctionCaller$FieldSetter

    我已尝试一切方法来消除此错误 但它不断出现 Class kotlin reflect jvm internal FunctionCaller FieldSetter can not access a member of class com
  • android device.getUuids 返回 null

    我正在尝试使用低功耗蓝牙 BLE 通过 Android 应用程序连接到 Arduino Uno 我正在 Android Studio 上进行开发 使用 Samsung Galaxy S4 和 Android 版本 5 0 1 进行测试我点击
  • 如何从Android webview下载文件?

    我下面的代码可以很好地加载 url 页面 并且在搜索歌曲后 当我单击下载链接时 它崩溃了 关于如何让下载管理器与网络视图一起工作的教程并不多 我究竟做错了什么 import java io File import android app A
  • 调用属于Fragment的Activity的函数

    我正在与多个Fragments在 Android 下 我对如何从嵌入式应用程序发送和接收数据感到困惑 为了简单的解释 我有一个ListFragment and a MapFragment使用解释的方法here https stackover
  • 使用Android Camera API,拍摄照片的方向始终未定义

    我使用相机API 拍摄的照片总是旋转90度 我想旋转它 所以首先我想知道图片的方向 这一点我被卡住了 我总是以两种方式得到未定义的方向 这是代码 Override public void onPictureTaken byte data C
  • 如何以相同的意图从相机获取全尺寸图片和缩略图

    我一直需要找到这个问题的解决方案 我已经从这个社区搜索并测试了许多解决方案 但任何人都适合帮助我 我有两个活动 第一个活动拍摄一张照片并将其发送到另一个活动 该活动有一个 ImageView 来接收该照片 直到这里我遇到问题 以及一个在数据
  • Android 布局仅使一个视图将自己绘制为横向,但其他所有视图都使用纵向

    我的活动布局中的主要视图元素是 VideoView 我的视频被渲染为设备的横向分辨率 但视频中的所有内容都是横向的 因此仍然需要在设备处于纵向位置时观看 即使我必须将活动设置为android screenOrientation landsc
  • 如何在 Android 应用程序退出之前进行一些清理?

    当我的 Android 应用程序终止时 是否有某种 onTerminate 方法可以进行一些清理 我想清除一些 SharedPreferences 我有一个活动 它保持几个数字的运行平均值 并将其存储在 SharedPreference 中
  • 活动构建变体没有测试工件

    我基于 调试 构建变体创建了一个名为 bitrise 的新构建类型 使用 debug 构建变体时 经过检测的 androidTests 构建并运行良好 但是当我切换到新的 bitrise 构建变体时 出现以下错误 Process finis
  • Android 使用不同的签名密钥更新市场应用程序

    开发人员使用他的个人密钥库签署了应用程序 但它应该是公司的密钥库 现在是否可以使用公司的密钥库更新市场中的应用程序 并且仍然可以简化对用户的更新 这有什么后果吗 不可以 您必须将该应用程序作为新应用程序发布到市场上 这次是用公司的key签名

随机推荐

  • Java 递归暴力迷宫求解器

    在尝试编写一个强力解决迷宫的 C 程序时 我首先编写了这个 java 程序来测试一个想法 我对 C 很陌生 打算在 Java 中正确使用它后将其转换 因此 我尝试远离数组列表 花哨的库等 以便更容易转换为 C 该程序需要生成最短步骤的单宽度
  • PHP 和 Wordpress 中的调试

    ini set log errors On and define WP DEBUG true 我正在尝试创建一个错误日志文件 但我对这两个文件感到困惑 会出现什么样的错误log errors and WP DEBUG The define
  • 使用 C# 从 SQL Server 数据生成 XML

    我在 SQL Server 中有一个生成 XML 输出的查询 我想使用 C 产生相同的结果 是否可以 查询是 select T1 1 HomeID as HomeID select T1 2 DayID as ID select T2 Rn
  • com.sun.xml.internal.ws.client 不存在

    我试图捕获 ClientTransportException 但我的程序在编译阶段失败 出现以下异常 ERROR workspace rates java service bundle1 src main java com connecto
  • 有没有办法知道 NSUserNotificationCenter 中有多少个 NSUserNotification?

    Is there any non private way of knowing how many notifications there are in the Notification Center NSUserNotificationCe
  • 为什么 PDO fetchColumn() 在这里不起作用

    我正在尝试计算查询返回的行数 我正在这样做 what Norman stmt conn gt prepare select names as names from names where names what stmt gt bindPar
  • 如何为文本框添加效果到样式

    我试图向样式添加效果以便重用它 但由于某种原因它不起作用
  • Spring REST 返回 PDF - 响应状态 406(不可接受)

    我读了很多关于此类问题的问题 但他们都建议使用正确的杰克逊版本 这是我目前的情况 休息 API RequestMapping value get pdf id headers Accept method RequestMethod GET
  • Swift Combine:将发布者转变为只读 CurrentValueSubject

    有时我的视图模型使用 Published财产或PassthroughSubject 但我不希望它对外界可写 很简单 把它变成公共的AnyPublisher并将可写的保留为私有 如下所示 class ViewModel Published p
  • Google API Oauth .net core 3.1

    我有一个 net core 3 1 MVC Web 应用程序 我正在尝试开始使用一些谷歌 API 我发现谷歌文 档非常混乱 在官方文档中 我发现 MVC 库不支持 net core 有人可以为我指明正确的方向 我应该如何开始在 MVC ne
  • 使用 ArcGIS JS API 的 dojo 解析器和 TypeError

    我收到此错误 类型错误 未定义 不是函数 评估 parser parse 这是我的代码
  • 未启用时更改按钮背景

    我需要改变我的Button仅当未启用背景 例如 SolidColorBrush 时 IsEnabled false 我能怎么做 我要修改按钮吗Style使用 XAML 或者我可以通过编程方式完成这项工作吗 在未启用背景时仅更改背景的正确 X
  • 使用 jQuery 按顺序添加和删除类

    我想说的是 如果我的 div 没有活动类 请添加它 如果该类确实处于活动状态 请将其删除 我有以下内容 只有我的代码添加了该类 然后继续查询并在最后删除它 最好的解决方案是什么 2个单独的单击功能 work showcase click f
  • Woocommerce 根据所选的运输类别在结账时更改运输方式标题

    我想根据产品的运输类别更改商店结帐中显示的运输方式标题 e g 运输方式标题目前为统一费率 我有 2 个产品 如果购买产品 A 我需要它有 易碎品运输 如果购买产品 B 我需要它具有 标准运输 遗憾的是 我必须使用类来进行运输 因此其他方法
  • Angular 2 服务的异步初始化

    我有一个 Angular 2 服务 需要在初始化时执行异步工作 并且在初始化完成之前不应该使用 Injectable export class Api private user private storage constructor pri
  • Numpy 数组广播规则

    我在理解 Numpy 中数组广播的规则时遇到一些困难 显然 如果对两个具有相同维度和形状的数组执行逐元素乘法 一切都很好 另外 如果将多维数组乘以标量 它就会起作用 这我明白了 但是如果你有两个 N 维数组不同的形状 我不清楚广播规则到底是
  • 检测到 jQuery.ajax 调用因页面正在重新加载而失败?

    我进行了大量的 ajax 调用 并以抛出消息的方式处理来自它们的错误 我发现如果在页面重新加载时正在进行 ajax 调用 例如单击刷新 或导航到另一个 URL 然后我正在进行的 ajax 调用会触发它们的错误回调 如何区分真正的错误和因页面
  • 向 qmake 添加一个带有值的定义?

    如何使用 qmake 添加带有值的定义 例如 这在我的 pro 文件中不起作用 如我所料 DEFINES WINVER 0x0500 nor DEFINES WINVER 0x0500 如何在开始编译之前将 WINVER 定义为 0x050
  • 如何隐藏DataGridView的网格线? Winforms C#

    如何隐藏DataGridView的网格线 我在互联网上搜索过但没有找到解决方案 请帮忙 谢谢 你可以试试 MyGrid CellBorderStyle DataGridViewCellBorderStyle None
  • Android Spannable:如何清除颜色?

    我在 RecyclerView CardViews 的 SearchView 上设置了 Spannable 如果在 CardView 上找到用户输入的文本 则该文本将以红色突出显示 当 SearchView 行被清除时 我希望 CardVi