I have recently added a bounty to this SO question, but realise the original question asks for a SimpleAdapter and not an ArrayAdapter. So, this question relates to the Arra
Sam has already given an excellent answer But there is one very short problem For example, if I wanted to search for "a thing", I might enter "thing a". This will not work. However, the code above contains a short section which tries to return the words 'in order'. And you need to make some changes in it to get the best solution.
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
// Break the prefix into "words"
final String[] prefixes = prefixString.split(" ");
final int prefixCount = prefixes.length;
int loc;
// Find the first "word" in prefix
if(valueText.startsWith(prefixes[0]) || (loc = valueText.indexOf(' ' + prefixes[0])) > -1)
loc = valueText.indexOf(prefixes[0]);
// Find the following "words"
for (int j = 1; j < prefixCount && loc > -1; j++)
loc = valueText.indexOf(prefixes[j]);
// If every "word" is in this row, add it to the results
if(loc > -1)
newValues.add(value);
}
I have removed loc + 2 from Sam's answer this line
for (int j = 1; j < prefixCount && loc > -1; j++)
loc = valueText.indexOf(' ' + prefixes[j], loc + 2);
I thought I would share my modified version of Sam's excellent answer. I just made 2 minor changes to support multi-line text in both the filter string and the text being filtered:
final String valueText = value.toString().toLowerCase().replace('\r', ' ').replace('\n', ' ');
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
// Break the prefix into "words"
final String[] prefixes = prefixString.split("\\s+");
final int prefixCount = prefixes.length;
int loc;
// Find the first "word" in prefix
if(valueText.startsWith(prefixes[0]) || (loc = valueText.indexOf(' ' + prefixes[0])) > -1)
loc = valueText.indexOf(prefixes[0]);
// Find the following "words" in order
for (int j = 1; j < prefixCount && loc > -1; j++)
loc = valueText.indexOf(' ' + prefixes[j], loc + 2);
// If every "word" is in this row, add it to the results
if(loc > -1)
newValues.add(value);
}
I just replace \r and \n with spaces. You could also remove other white-space if needed, such as \t, or change to a regular expression... for me \r and \n was enough. I also changed the split() to \s+ so that it splits on any white-space.
[Complementing the sam's response] Your code will have problems when you digites only spaces. I added an "if".
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
// Break the prefix into "words"
final String[] prefixes = prefixString.split(" ");
final int prefixCount = prefixes.length;
// HERE CHANGE
if (prefixCount>0) {
int loc;
// Find the first "word" in prefix
if (valueText.startsWith(prefixes[0]) || (loc = valueText.indexOf(' ' + prefixes[0])) > -1)
loc = valueText.indexOf(prefixes[0]);
// Find the following "words" in order
for (int j = 1; j < prefixCount && loc > -1; j++)
loc = valueText.indexOf(' ' + prefixes[j], loc + 2);
// If every "word" is in this row, add it to the results
if (loc > -1)
newValues.add(value);
}
}
Unfortunately ArrayAdapter and other built-in adapters don't allow you to change their existing filters. There is no setFilter()
method in the API... You must create a custom adapter that performs the same functions as ArrayAdapter.
To do this: simply cut & paste ArrayAdapter's source code into a new class in your project. Then find the Filter at the bottom. Inside performFiltering()
we'll make a few changes. Find the if-else block marked with the following comment and replace that code block with this:
// First match against the whole, non-splitted value
if (valueText.startsWith(prefixString)) {
newValues.add(value);
} else {
// Break the prefix into "words"
final String[] prefixes = prefixString.split(" ");
final int prefixCount = prefixes.length;
int loc;
// Find the first "word" in prefix
if(valueText.startsWith(prefixes[0]) || (loc = valueText.indexOf(' ' + prefixes[0])) > -1)
loc = valueText.indexOf(prefixes[0]);
// Find the following "words" in order
for (int j = 1; j < prefixCount && loc > -1; j++)
loc = valueText.indexOf(' ' + prefixes[j], loc + 2);
// If every "word" is in this row, add it to the results
if(loc > -1)
newValues.add(value);
}
That's it. We only had to change the section of code above to meet your requirements, but we have to copy the entire adapter into a class since there is no other way to makes these changes.
(PS Since you've already created a new class, you might as well optimize getView()
to suit you needs. The generic method is slower than it needs to be for a custom class.)
Currently the only solution to achive what you want is overriding the ArrayAdapter
and implement your own filtering requirements.
This requires a lot of code, as Filter
in ArrayAdapter
is using a lot of private objects, that you will need to replicate.
Fortunatly, someone else (@uʍop ǝpısdn) already went to the process, wrote the code and made it available for the community.
You can find the link to is blog here including how to use examples, and the code in here.
Regards.