I am using a MultiAutoCompleteTextView which shows suggestions for user input. It only works when the items are separated by one or more spaces, but doesn't when a new line (i.e. button "enter" is pressed) is the delimiter.
The code so far (I think I got it from stackoverflow some time ago):
public class SpaceTokenizer implements Tokenizer {
#Override
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != ' ') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
#Override
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
#Override
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
}
}
I tried to implement something like "... || text.charAt(i) == '\n' ..." where I thought appropriate, but that didn't work.
So I would be very thankful for suggestions!
The answer to my question can be found here:
Android and the CommaTokenizer
Related
My problem is that when I suggest sentences in MultiAutoCompleteTextView, when I press spacebar, the suggestions disappear.
Example:
Suggested words:
THE ROCK THE BALL THERMAL
If I write "THE", all sentences are displayed, but if I write "THE " (with blank space) the suggestions are dismissed.
I want that if you write "THE ", the elements "THE ROCK" and "THE BALL" are displayed in suggested words.
Thanks.
You should implement MultiAutoCompleteTextView.Tokenizer and create a spaceTokenizer as below. Then set multiAutoCompleteTextView.setTokenizer(new SpaceTokenizer());
public class SpaceTokenizer implements MultiAutoCompleteTextView.Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != ' ') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
}
}
Have a look at this post:
https://groups.google.com/forum/#!topic/android-developers/OrsN2xRpDmA
I just ran into a similar problem and wrote a simple multi word derivation. It defaults to a "," separator but you can set it whatever you like using the "setSeparator" method.
or
this stack-overflow answer might be helpful cause it experiences the same problem:
AutoCompleteTextView backed by CursorLoader
i have two adpters in my app with separate listview
one is for user and another one is for groups
i want set the adapter to the textview when the conditon exists like when the user types a token '#' the user adapter should be set and when the user types a token '#' the channel adapter(for populating list of groups) should be set
my adapters:
final ChannelAdapter customadapter1 = new ChannelAdapter(getActivity(), R.layout.all_cahnnel_list_item, joinOtherChannelList);
final UserAdapter customadapter = new UserAdapter(getActivity(), R.layout.all_user_list_item, userArrayList);
inputMessageView = (MultiAutoCompleteTextView) view.findViewById(R.id.message_input);
inputMessageView.setThreshold(0);
inputMessageView.setTokenizer(new MultiAutoCompleteTextView.Tokenizer() {
#Override
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(), Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
}
#Override
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (((i > 0 && text.charAt(i - 1) != '#') && (i > 0 && text.charAt(i - 1) != '#'))) {
i--;
}//Check if token really started with #, else we don't have a valid token
if (text.charAt(i - 1) != '#') {
inputMessageView.setAdapter(customadapter);
return cursor:
} else if (i < 1 || text.charAt(i - 1) != '#') {
inputMessageView.setAdapter(customadapter1);
return cursor;
}
return i;
}
#Override
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
});
My problem is when i use if condition alone its working for custom adapter one. But when i use if and else if to set both adapter not even single adapter is working i mean its not displaying anything in the text view
Your conditions aren't same.
if (text.charAt(i - 1) != '#') {
inputMessageView.setAdapter(customadapter)
return cursor;
} else if (i < 1 || text.charAt(i - 1) != '#') {
inputMessageView.setAdapter(customadapter2);
return cursor;
}
If , as you said, works on one if conditions then it should work, because else if part doesn't gets executed. Try using logs and try printing the logs.
I have a MultiAutoCompleteTextView. It works fine. But I want to show suggestion dropdown only when user type # on it (like tagging user in facebook app). I have no idea how to do it. Here is my code :
mChatbox = (MultiAutoCompleteTextView) findViewById(R.id.chatbox);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line, userList);
mChatBox.setAdapter(adapter);
mChatBox.setTokenizer(new SpaceTokenizer());
public class SpaceTokenizer implements MultiAutoCompleteTextView.Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != ' ') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
}
Create a custom Text view extending MultiAutoCompleteTextView -> override enoughToFilter() -> set the threshold to 0 (the bold variable in the below given code) :
public boolean enoughToFilter() {
Editable text = getText();
int end = getSelectionEnd();
if (end < 0 || mTokenizer == null) {
return false;
}
int start = mTokenizer.findTokenStart(text, end);
if (end - start >= mThreshold && start != -1) {
return true;
} else {
return false;
}
}
Using this code you'll see the auto suggested list on press of #
If you want to detect your string starts with '#' for mention (tag) someone or '#' for hashTag, then do query or filter with it, you could follow this code belows:
#Override
public void onTextChanged(CharSequence s, int start, int before, final int count) {
if (s.length() > 0) {
// Todo: query mentions
Matcher mentionMatcher = Pattern.compile("#([A-Za-z0-9_-]+)").matcher(s.toString());
// while matching
while (mentionMatcher.find()) {
yourSearchText = s.toString().substring(mentionMatcher.start() + 1, mentionMatcher.end());
// do query with yourSearchText below
}
}
}
It references from the link Multiautocompletetextview, Show autocomplete drop down only when user presses a key after '#' key (like mention in FB app) please scroll down to find #Phuong Sala answer.
I got a solution by myself. I create custom view which extends MultiAutoCompleteTextView and override performFiltering in it. Check if first char is "#", then filter the next chars after it. Otherwise, replace chars with "*" to avoid filtering. Here is my code.
#Override
protected void performFiltering(CharSequence text, int start, int end, int keyCode) {
if (text.charAt(start) == '#') {
start = start + 1;
} else {
text = text.subSequence(0, start);
for (int i = start; i < end; i++) {
text = text + "*";
}
}
super.performFiltering(text, start, end, keyCode);
}
i integrated MultiAutoCompleteTextView in to my dictionary app so now after integrating it.
i got a problem like this as show in second screen shot...
so now i don't want that ","
as show in second screen shots after !
i am getting "," like this
!,
plz help me
thank q
String[] str={"!","\"","#","$","$1","%","'","+",",","/"};
MultiAutoCompleteTextView mt=(MultiAutoCompleteTextView)findViewById(R.id.searchEditText);
mt.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
ArrayAdapter<String> adp=new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,str);
mt.setThreshold(1);
mt.setAdapter(adp);
The comma is coming from CommaTokenizer() called in this line mt.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
To remove the comma you need to implement your own Tokenizer. This is an example:
public class SpaceTokenizer implements Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != ' ') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
}
}
PS: I copied the code from this answer
I'm doing a simple program using MultiAutoCompleteTextView to prompt the common words when I input several letters.
code:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
this,
android.R.layout.simple_dropdown_item_1line,
ary);
MultiAutoCompleteTextView textView = (MultiAutoCompleteTextView) findViewById(R.id.editText);
textView.setAdapter(adapter);
textView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
private String[] ary = new String[] {
"abc",
"abcd",
"abcde",
"abcdef",
"abcdefg",
"hij",
"hijk",
"hijkl",
"hijklm",
"hijklmn",
};
Now,when I input 'a' and choose "abcd" but the result become to "abcd,". How to replace the comma with a space?
Thank you!
public class SpaceTokenizer implements Tokenizer {
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != ' ') {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == ' ') {
return i;
} else {
i++;
}
}
return len;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == ' ') {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text + " ");
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + " ";
}
}
}
}
The way to do it would be to implement your own Tokenizer. The reason the comma comes up is because you're using CommaTokenizer, which is designed to do exactly that. You can also look at the source code for CommaTokenizer if you need a reference for how to implement your own SpaceTokenizer.
Check my question/answer
How to replace MultiAutoCompleteTextView drop down list
you will find a SpaceTokenizer class
I have used Kotlin for a white space tokenizer. This also caters tabs, trailing spaces and line feeds.
object : Tokenizer {
override fun findTokenStart(text: CharSequence, cursor: Int): Int {
val spaceIndex = text.indexOfFirst { Character.isWhitespace(it) }
return if (spaceIndex > cursor)
spaceIndex
else cursor
}
override fun findTokenEnd(text: CharSequence, cursor: Int): Int {
val lastSpaceIndex = text.indexOfLast { Character.isWhitespace(it) }
return if (lastSpaceIndex > cursor)
lastSpaceIndex
else cursor
}
override fun terminateToken(text: CharSequence): CharSequence {
val i = text.length
return if (i > 0 && text[i - 1] == ' ') {
text
} else {
if (text is Spanned) {
val sp = SpannableString("$text ")
TextUtils.copySpansFrom(
text as Spanned?, 0, text.length,
Any::class.java, sp, 0
)
sp
} else {
"$text "
}
}
}
}