¿Cómo resalto el texto buscado en mi filtro de búsqueda?
Estoy intentando hacer una búsqueda tal que todas las letras "visibles" de la búsqueda se deben destacar. Intenté usar spannable pero eso no hizo el truco, quizás no lo hice derecho? Basado en esto: Resalte el texto buscado en los elementos ListView ¿Cómo puedo resaltar el texto visible? Aquí está mi filtro:
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!
Aquí está mi getview
- ¿Cómo buscar una palabra en una cadena y resaltar una palabra en una vista de texto en android?
- Cómo cambiar fontFamily de TextView en Android
- Formato HTML para TextView
- El texto de Android TextView no aparece en los dispositivos Samsung
- Android: dibujar línea en una vista de texto
@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; }
- Alineación derecha del texto en Android TextView
- TextView rellenado dinámicamente cortando la última línea de texto
- Cómo ampliar una vista de texto en android?
- Android TextView no se actualiza completamente
- ¿Establecer etiquetas para cada elemento en un ListView en Android?
- Alinear la imagen dibujable dentro de una vista de texto para centrarse
- Cómo establecer un texto sobre una imagen?
- Alinear dos TextViews, una izquierda a la otra derecha, en un ListView sin estirar los fondos
Supongamos que tiene crear un adaptador personalizado, a continuación, puede consultar el código siguiente:
@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; }
El mSearchText
se actualizará en la siguiente performFiltering
dentro de performFiltering
de ArrayFilter
.
String prefixString = prefix.toString().toLowerCase(); mSearchText = prefixString;
Puede encontrar más detalles en mi código de ejemplo aquí o en mi GitHub (con la última actualización) .
Aquí está la captura de pantalla
En su método de filtro , almacene la cadena utilizada para realizar el filtro:
// Filter Class public void filter(String searchString) { this.searchString = searchString; ... // Filtering stuff as normal. }
Debe declarar una cadena de miembro para almacenarla:
public class ListViewAdapter extends BaseAdapter { ... String searchString = ""; ...
Y, en getView resalta el término de búsqueda:
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); } ... }
Espero eso ayude.
Esto es sólo demo para resaltar texto, puede implementar su auto llamando a highlight(searchText, originalText)
en el filtro,
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; } } }
Ponga este código antes de establecer el texto en 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);
Hola en tu clase del adaptador, haces un texto del spanneble y lo fijas a tu textview, el código abajo que puedes utilizar para la referencia.
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); }
- Cómo hacer que el primer carácter sea mucho más grande que otro en un TextView
- Posible obtener detalles de error específicos de Android SQLiteConstraintException?