我有一个的ListView
与字符串
秒。随着低于code,我可以突出显示搜索结果,但用户必须键入要搜索的词区分大小写。 我如何实现一个无 - ?情况下的搜索结果,例如像原生的Android联系人搜索敏感的语法高亮
下面是我的code为突出。我延长 ArrayAdapter
和实施定制过滤器,以获取字符串进行搜索。在 getView
方法检查我的字符串
ListView中包含 prefixString
并突出显示。
公共类HighlightListAdapter扩展ArrayAdapter {
ArrayList的<字符串>对象;
最终目标MLOCK =新的对象();
私人的ArrayList<字符串> mOriginalValues;
私人ArrayFilter过滤器;
私人字符串prefixString;
公共AuthorsListAdapter(上下文的背景下,INT textViewResourceId,ArrayList的<字符串>对象){
超(背景下,textViewResourceId,对象);
this.objects =物体;
}
类ViewHolder {
TextView的作者;
}
公共查看getView(最终诠释的立场,观点convertView,ViewGroup中父){
//指定我们正在转换到一个局部变量视图
视图V = convertView;
ViewHolder支架=无效;
//首先检查是否视图为空。如果是这样,我们要它充气。
//夸大它的基本含义来呈现,或秀,景色。
LayoutInflater充气=(LayoutInflater)的getContext()getSystemService(Context.LAYOUT_INFLATER_SERVICE)。
如果(V == NULL){
持有人=新ViewHolder();
V = inflater.inflate(R.layout.author_list_item,NULL);
holder.author =(TextView中)v.findViewById(R.id.author_list_item_text);
v.setTag(保持器);
}其他{
支架=(ViewHolder)v.getTag();
}
最后弦乐笔者= objects.get(位置);
如果(作家!= NULL){
holder.author.setText(作者);
如果(prefixString =空&安培;!&安培; prefixString.length()→1){
字符串s =作者;
**如果(s.contains(prefixString)){
字符串代表= s.replace(prefixString,< B><字体颜色=#2825A6>+ prefixString +< / FONT>< / B>中);
holder.author.setText(Html.fromHtml(REP));
} ** // higlight
}
}
返回伏;
}
@覆盖
公众诠释getCount将(){
// TODO自动生成方法存根
返回objects.size();
}
@覆盖
公共过滤用getFilter(){
// TODO自动生成方法存根
如果(过滤== NULL){
过滤器=新ArrayFilter();
}
返回过滤器;
}
@覆盖
公共对象的getItem(INT位置){
// TODO自动生成方法存根
返回this.objects.get(位置);
}
私有类ArrayFilter扩展过滤器{
@覆盖
保护FilterResults performFiltering(CharSequence的preFIX){
FilterResults结果=新FilterResults();
如果(mOriginalValues == NULL){
同步(MLOCK){
mOriginalValues =新的ArrayList<字符串>(对象);
}
}
如果(preFIX == NULL || prefix.length()== 0){
ArrayList的<字符串>清单;
同步(MLOCK){
名单=新的ArrayList<字符串>(mOriginalValues);
}
results.values =清单;
results.count =则为list.size();
} 其他 {
** prefixString = prefix.toString(); // **弄的字符串搜索
ArrayList的<字符串>值;
同步(MLOCK){
值=新的ArrayList<字符串>(mOriginalValues);
}
最终诠释计数= values.size();
最后的ArrayList<字符串> newValues =新的ArrayList<字符串>();
的for(int i = 0; I<计数;我++){
最终的字符串值= values.get(我);
最后弦乐valueText = value.toString()与toLowerCase()。
//首先对整场比赛,非分裂值
如果(valueText.startsWith(prefixString)){
newValues.add(值);
} 其他 {
最终的String []字= valueText.split();
最后的wordCount INT = words.length;
//开始在索引0,如果valueText开始与空间(S)
对于(INT K = 0; K<的wordCount; k ++){
如果(字[K] .startsWith(prefixString)){
newValues.add(值);
打破;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
返回结果;
}
@燮pressWarnings(未登记)
@覆盖
保护无效publishResults(CharSequence的约束,FilterResults结果){
对象=(ArrayList的<字符串>)results.values;
如果(results.count大于0){
notifyDataSetChanged();
} 其他 {
notifyDataSetInvalidated();
}
}
};
}
解决方案
本我用的:
在每一次出现被替换(不仅是preFIX) 案例和重音被忽略,而搜索,但保留在结果中。 在这直接使用 SpannableString
,您可以在的setText使用()
。我相信这是比使用一个中间步骤HTML更有效。
公共静态CharSequence的亮点(字符串搜索,字符串originalText){
//忽略大小写和重音
//同样的事情应该已经做了搜索文本
串normalizedText = Normalizer.normalize(originalText,Normalizer.Form.NFD).replaceAll(\\ p {InCombiningDiacriticalMarks} +,).toLowerCase();
INT开始= normalizedText.indexOf(搜索);
如果(开始℃,){
//没有发现,没有向
返回originalText;
} 其他 {
//突出原文每次出现
//在标准化文本搜索,而
Spannable强调=新SpannableString(originalText);
同时(开始> = 0){
INT spanStart = Math.min(启动,originalText.length());
INT spanEnd = Math.min(开始+ search.length(),originalText.length());
highlighted.setSpan(新BackgroundColorSpan(小于background_color&1+),spanStart,spanEnd,Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
启动= normalizedText.indexOf(搜索,spanEnd);
}
返回突出;
}
}
I have a ListView
with String
s. With the below code I can highlight search results, but the user must type the words to search case sensitive. How can I implement a none - case sensitive highlighting of search results for example like the native Android Contact search?
Here is my code for Highlighting. I extend the ArrayAdapter
and implement customized filter to get the string to search. In the getView
method I check if my String
in ListView contains the prefixString
and highlight it.
public class HighlightListAdapter extends ArrayAdapter {
ArrayList<String> objects;
final Object mLock =new Object();
private ArrayList<String> mOriginalValues;
private ArrayFilter filter;
private String prefixString;
public AuthorsListAdapter(Context context, int textViewResourceId, ArrayList<String> objects) {
super(context, textViewResourceId, objects);
this.objects = objects;
}
class ViewHolder{
TextView author;
}
public View getView(final int position, View convertView, ViewGroup parent){
// assign the view we are converting to a local variable
View v = convertView;
ViewHolder holder = null;
// first check to see if the view is null. if so, we have to inflate it.
// to inflate it basically means to render, or show, the view.
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (v == null) {
holder = new ViewHolder();
v = inflater.inflate(R.layout.author_list_item, null);
holder.author =(TextView) v.findViewById(R.id.author_list_item_text);
v.setTag(holder);
}else{
holder = (ViewHolder) v.getTag();
}
final String author = objects.get(position);
if (author != null) {
holder.author.setText(author);
if(prefixString !=null && prefixString.length()>1){
String s = author;
**if(s.contains(prefixString)){
String rep = s.replace(prefixString, "<b><font color=#2825A6>"+ prefixString+ "</font></b>");
holder.author.setText(Html.fromHtml(rep));
}** // higlight
}
}
return v;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return objects.size();
}
@Override
public Filter getFilter() {
// TODO Auto-generated method stub
if(filter == null){
filter =new ArrayFilter();
}
return filter;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return this.objects.get(position);
}
private class ArrayFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence prefix) {
FilterResults results = new FilterResults();
if (mOriginalValues == null) {
synchronized (mLock) {
mOriginalValues = new ArrayList<String>(objects);
}
}
if (prefix == null || prefix.length() == 0) {
ArrayList<String> list;
synchronized (mLock) {
list = new ArrayList<String>(mOriginalValues);
}
results.values = list;
results.count = list.size();
} else {
**prefixString = prefix.toString();** // get string to search
ArrayList<String> values;
synchronized (mLock) {
values = new ArrayList<String>(mOriginalValues);
}
final int count = values.size();
final ArrayList<String> newValues = new ArrayList<String>();
for (int i = 0; i < count; i++) {
final String value = values.get(i);
final String valueText = value.toString().toLowerCase();
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
final String[] words = valueText.split(" ");
final int wordCount = words.length;
// Start at index 0, in case valueText starts with space(s)
for (int k = 0; k < wordCount; k++) {
if (words[k].startsWith(prefixString)) {
newValues.add(value);
break;
}
}
}
}
results.values = newValues;
results.count = newValues.size();
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
objects = (ArrayList<String>) results.values;
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
};
}
解决方案
This what I use :
Every occurence is replaced (not only prefix) Case and accent are ignored while searching but retained in the result. It uses directlySpannableString
, which you can use in setText()
. I believe it's more efficient than using an intermediate html step.
.
public static CharSequence highlight(String search, String originalText) {
// ignore case and accents
// the same thing should have been done for the search text
String normalizedText = Normalizer.normalize(originalText, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "").toLowerCase();
int start = normalizedText.indexOf(search);
if (start < 0) {
// not found, nothing to to
return originalText;
} else {
// highlight each appearance in the original text
// while searching in normalized text
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(<background_color>), spanStart, spanEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = normalizedText.indexOf(search, spanEnd);
}
return highlighted;
}
}