如何在搜索过滤器中突出显示搜索到的文本?

时间:2015-10-29 15:07:17

标签: android android-layout android-fragments textview android-search

我正在尝试搜索所有"可见"搜索字母应突出显示。我尝试过使用spannable但是没有做到这一点,也许我没有做到这一点?基于此:Highlight searched text in ListView items 如何突出显示可见文本?这是我的过滤器:

private LayoutInflater mInflater;

        private ValueFilter valueFilter;

        public MySimpleArrayAdapter(Activity context) {

            this.context = context;
            mInflater = LayoutInflater.from(context);

        }
        private class ValueFilter extends Filter {


            //Invoked in a worker thread to filter the data according to the constraint.
            @Override
            protected synchronized FilterResults performFiltering(CharSequence constraint) {

                FilterResults results = new FilterResults();

                if (constraint != null && constraint.length() > 0) {

                    ArrayList<Integer> filterList = new ArrayList<>();

                    int iCnt = listItemsHolder.Names.size();
                    for (int i = 0; i < iCnt; i++) {
                        if(listItemsHolder.Types.get(i).toString().indexOf("HEADER_")>-1){
                            continue;
                        }
                        if (listItemsHolder.Names.get(i).matches(getRegEx(constraint))||(listItemsHolder.Names.get(i).toLowerCase().contains(constraint.toString().toLowerCase()))) {
                            if(filterList.contains(i))
                                continue;

                            filterList.add(i);

                        }
                        }

                    results.count = filterList.size();

                    results.values = filterList;
                }else {
                String prefixString = getRegEx(constraint);
                mSearchText = prefixString;
                    results.count = listItemsHolder.Names.size();

                    ArrayList<Integer> tList = new ArrayList<>();
                    for(int i=0;i<results.count;i++){
                        tList.add(i);
                    }

                    results.values = tList;

                }

                return results;


}


                //Invoked in the UI thread to publish the filtering results in the user interface.
                @SuppressWarnings("unchecked")
                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    ArrayList<Integer> resultsList = (ArrayList<Integer>)results.values;
                    if(resultsList != null) {
                        m_filterList = resultsList;
                    }
                    notifyDataSetChanged();
                }

            }

            public String getRegEx(CharSequence elements){
                String result = "(?i).*";
                for(String element : elements.toString().split("\\s")){
                    result += element + ".*";
                }
                result += ".*";
                return result;
            }

Thanks in advance! 

这是我的获取视频

@Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View rowView = convertView;
            ViewHolder holder;
            if(filtering && m_filterList != null && m_filterList.size() > position)
                position = m_filterList.get(position);

            if (rowView == null) {
                holder = new ViewHolder();

                mInflater = context.getLayoutInflater();
                rowView = mInflater.inflate(R.layout.rowlayout, null);
                // configure view holder
                holder.text = (TextView) rowView.findViewById(R.id.label);
                holder.text.setTextColor(Color.WHITE);
                holder.text.setSingleLine();
                holder.text.setTextSize(15);
                holder.text.setEllipsize(TextUtils.TruncateAt.END);
                holder.text.setPadding(2, 2, 6, 2);
                Typeface label = Typeface.createFromAsset(holder.text.getContext().getAssets(),
                        "fonts/arial-bold.ttf");
                holder.text.setTypeface(label);
                holder.image = (ImageView) rowView.findViewById(R.id.icon);
                holder.image.setPadding(6, 4, 0, 4);
                holder.image.getLayoutParams().height = (int) getResources().getDimension(R.dimen.icon_width_height);
                holder.image.getLayoutParams().width = (int) getResources().getDimension(R.dimen.icon_width_height);
                rowView.setBackgroundResource(R.drawable.row_border);
                rowView.setPadding(2, 2, 6, 2);
                rowView.setTag(holder);
            }else {

                // fill data
                holder = (ViewHolder) rowView.getTag();
            }

            String id  = listItemsHolder.getid(position);
            String name = listItemsHolder.getName(position);
            holder.image.setVisibility(View.VISIBLE);


            if (name != null) {
                holder.text.setText(listItemsHolder.getName(position));
                ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) holder.text.getLayoutParams();
                params.leftMargin = 20;
            }else{
                holder.text.setText(id);
            }
            String fullText = listItemsHolder.getName(position);
            // highlight search text
            if (mSearchText != null && !mSearchText.isEmpty()) {
                int startPos = fullText.toLowerCase(Locale.US).indexOf(mSearchText.toLowerCase(Locale.US));
                int endPos = startPos + mSearchText.length();
                if (startPos != -1) {
                    Spannable spannable = new SpannableString(fullText);
                    ColorStateList blueColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{Color.BLUE});
                    TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, blueColor, null);
                    spannable.setSpan(highlightSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                    holder.text.setText(spannable);
                } else {
                    holder.text.setText(fullText);
                }
            } else {
                holder.text.setText(fullText);
            }
            return rowView;
        }

6 个答案:

答案 0 :(得分:15)

假设您已经创建了自定义适配器,那么您可以参考以下代码:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        TextView text;

        if (convertView == null) {
            view = mInflater.inflate(mResource, parent, false);
        } else {
            view = convertView;
        }

        try {
            if (mFieldId == 0) {
                //  If no custom field is assigned, assume the whole resource is a TextView
                text = (TextView) view;
            } else {
                //  Otherwise, find the TextView field within the layout
                text = (TextView) view.findViewById(mFieldId);
            }
        } catch (ClassCastException e) {
            Log.e("ArrayAdapter", "You must supply a resource ID for a TextView");
            throw new IllegalStateException(
                    "ArrayAdapter requires the resource ID to be a TextView", e);
        }
        String item = getItem(position);
        text.setText(item);

        String fullText = getItem(position);
        // highlight search text
        if (mSearchText != null && !mSearchText.isEmpty()) {
            int startPos = fullText.toLowerCase(Locale.US).indexOf(mSearchText.toLowerCase(Locale.US));
            int endPos = startPos + mSearchText.length();

            if (startPos != -1) {
                Spannable spannable = new SpannableString(fullText);
                ColorStateList blueColor = new ColorStateList(new int[][]{new int[]{}}, new int[]{Color.BLUE});
                TextAppearanceSpan highlightSpan = new TextAppearanceSpan(null, Typeface.BOLD, -1, blueColor, null);
                spannable.setSpan(highlightSpan, startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                text.setText(spannable);
            } else {
                text.setText(fullText);
            }
        } else {
            text.setText(fullText);
        }

        return view;
    }

mSearchText将在performFilteringArrayFilter内的String prefixString = prefix.toString().toLowerCase(); mSearchText = prefixString; 内更新。

@LogMetrics
def my_business_logic(var1):
  print 'done'

您可以在my sample code heremy GitHub (with lastest update)中找到更多详细信息。

这是截图

enter image description here

答案 1 :(得分:3)

过滤器方法中,存储用于执行过滤器的字符串:

// Filter Class
public void filter(String searchString) {
    this.searchString = searchString;
    ...
    // Filtering stuff as normal.
}

您必须声明一个成员字符串来存储它:

public class ListViewAdapter extends BaseAdapter {
    ...    
    String searchString = "";
    ...

并且,在 getView 中,您会突出显示搜索字词:

public View getView(final int position, View view, ViewGroup parent) {
    ...
    // Set the results into TextViews
    WorldPopulation item = worldpopulationlist.get(position);
    holder.rank.setText(item.getRank());
    holder.country.setText(item.getCountry());
    holder.population.setText(item.getPopulation());

    // Find charText in wp
    String country = item.getCountry().toLowerCase(Locale.getDefault());
    if (country.contains(searchString)) {
        Log.e("test", country + " contains: " + searchString);
        int startPos = country.indexOf(searchString);
        int endPos = startPos + searchString.length();

        Spannable spanText = Spannable.Factory.getInstance().newSpannable(holder.country.getText()); // <- EDITED: Use the original string, as `country` has been converted to lowercase.
        spanText.setSpan(new ForegroundColorSpan(Color.RED), startPos, endPos, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        holder.country.setText(spanText, TextView.BufferType.SPANNABLE);
    }
    ...
}

希望它有所帮助。

答案 2 :(得分:2)

您好在您的适配器类上,制作一个spanneble文本并将其设置为textview,下面的代码可供您参考。

 if ("text contains filter value".toLowerCase().contains("filter".toLowerCase())) {
        Spannable spanText = Spannable.Factory.getInstance().newSpannable("text contains filter value".toLowerCase());

        Matcher matcher = Pattern.compile("filter".toLowerCase())
                .matcher("text contains filter value".toLowerCase());
        while (matcher.find()) {
            spanText.setSpan(new ForegroundColorSpan(Color.RED), matcher.start(),
                    matcher.start() + "filter".length(),
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        }
       yourTextView.setText(spanText);
    }

答案 3 :(得分:0)

这只是高亮文本的演示,您可以通过调用实现自己 过滤器中的highlight(searchText, originalText)

public class MainActivity extends AppCompatActivity {
EditText editText;
TextView text;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    editText = (EditText) findViewById(R.id.editText);
    text = (TextView) findViewById(R.id.textView1);

    editText.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) {
                text.setText(highlight(editText.getText().toString(), text.getText().toString()));
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    });

}

public static CharSequence highlight(String search, String originalText) {
    String normalizedText = Normalizer.normalize(originalText, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "").toLowerCase();
    int start = normalizedText.indexOf(search);
    if (start <= 0) {
        return originalText;
    } else {
        Spannable highlighted = new SpannableString(originalText);
        while (start > 0) {
            int spanStart = Math.min(start, originalText.length());
            int spanEnd = Math.min(start + search.length(), originalText.length());
            highlighted.setSpan(new BackgroundColorSpan(Color.YELLOW), spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            start = normalizedText.indexOf(search, spanEnd);
        }
        return highlighted;
    }
 }
}

答案 4 :(得分:0)

在getview

中设置文字之前输入此代码
Spannable wordtoSpan = new SpannableString("Your_text_in_getviews");

        wordtoSpan.setSpan(new ForegroundColorSpan(Color.RED), 0, edtFilter
                .getText().toString().length(),
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
txt_contact.setText(wordtoSpan);

答案 5 :(得分:0)

可以用更简单的方式完成:

  1. 定义自定义适配器:
class HighlightAutoCompleteAdapter(context: Context, resource: Int, private val textResId: Int, items: List<String>) :
    ArrayAdapter<String>(context, resource, textResId, items) {

    private val inflater = LayoutInflater.from(context)
    var queryText = ""

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = convertView ?: inflater.inflate(textResId, parent, false)
        val textView: TextView = view.findViewById(android.R.id.text1) as TextView
        val fullText = getItem(position) as String
        // highlight search text
        val highlight: Spannable = SpannableString(fullText)
        if (queryText.isNotEmpty()) {
            val startPos: Int = fullText.toLowerCase(Locale.US).indexOf(queryText.toLowerCase(Locale.US))
            val endPos: Int = startPos + queryText.length
            if (startPos != -1) {
                highlight.setSpan(StyleSpan(BOLD),
                                    startPos,
                                    endPos,
                                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            }
        }
        textView.text = highlight
        return view
    }
}
  1. 创建适配器并监听文本更改以保持适配器更新:
        val searchEditText: AutoCompleteTextView = view.findViewById(R.id.search_edit_text)
        val arrayAdapter = HighlightAutoCompleteAdapter(requireContext(), 0, R.layout.search_complete_item, autoCompletionList)
        searchEditText.setAdapter(arrayAdapter)
        searchEditText.addTextChangedListener(object : TextWatcher {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                arrayAdapter.queryText = s?.toString() ?: ""
            }
            override fun afterTextChanged(s: Editable?) {}
        })