MaterialChipsInput
MaterialChipsInput copied to clipboard
Can't change inputType, remove focus and suggestions
So this is just about the only library I've used so far that looks good and seems to work well for my needs but I have these two 'issues' and a suggestions that I've found from the limitations present with it.
Both the inputType and focus do nothing, whether I change it in the layout or in the code. It looks unprofessional having the EditText view always have the cursor in the EditText. A detail but my mild obsession with details makes me a bit annoyed about this.
InputType doesn't seem to be possible to change. I wanted to use the Enter/New line button has a delimiter to create a chip but in the current state I can't, making me use the comma. Not really an issue as it's still fully usable, but I'd like the option.
Suggestions:
By default there is no way to add a chip without suggestions, making it obligatory to write code in TextChanged and create our own logic and delimiters. This can be worked around but I'd prefer this to be optional, not mandatory if I want to add chips without having suggestions. This includes creating delimiters and letting the ChipsInput deal with the creation and trigger onChipAdded.
Override the comparison method. I don't know if the ChipValidator is supposed to deal with this but it does nothing, there's no mention of the Validator in the readme also which makes me a bit confused and Android Studio doesn't even find usages so any intentions of implementing this soon? I want to use this because my language and main language of the user will contain special chars and I want the user to not have to worry about writing special chars to find an already existing chip, specially when I already implemented this with a search function in other areas - this was also requested by an user, in this case my teacher.
Anyway, I've decided to use your library as it seems to accomplish the task well enough and is better than the ones I've already tried. Even with the complains I have, which are minor, I'll still keep it. Keep up the good work, specially seeing that this does seem to be the best to create chips. :)
Also forget to mention that chipsInput.setEnabled(false) or chipsInput.getEditText().setEnabled(false) also doesn't work. I've tried other methods to disable the view but can't seem to make it work. Still, I only needed it to show tags when in the trash in my app and not allow the user to edit them but since the trash is only really used to restore and permanently delete files, the tags aren't really necessary to be seen in this context. Hope that made sense.
Another suggestions as I keep messing around. Due to the focus never changing, it seems impossible to hide the dropdown suggestion view unless the user deletes all the text he wrote. I'd suggest at least fixing the focus issue or hiding the dropdown view when the focus is lost to not leave the dropdown hanging there.
I'm not sure if you are still updating this repo, but this would be a great addition. I'm also being forced to use commas as delimiters, which I don't feel like is intuitive to everyone using the app.
For anyone else interested, my hacky solution to add a chip on softkeyboard ENTER was to make an empty view in the XML layout IMMEDIATELY following the ChipsInput view.
It looks like this
<com.pchmn.materialchips.ChipsInput
android:id="@+id/chipsInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:textSize="18sp"
app:filterable_list_backgroundColor="@color/colorPrimary"
app:filterable_list_textColor="@color/textColorWhite"
app:hint="@string/search_contacts_hint"
app:maxRows="5"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="0dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_below="@+id/chipsInput"
android:id="@+id/divider"
/>
Note that I made the View focusable
and focusableInTouchMode
.
This way, when the user presses enter ON the ChipsInput, the next view to receive focus is always the View I made. I then added a setOnFocusChangedListener
to the empty view object like so:
divider.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean isFocused) {
Log.e(TAG, "isFocused " + isFocused);
if (isFocused) {
if (mSearchString != null && mSearchString.length() > 0) {
Log.e(TAG, mSearchString);
chipsSearchField.addChip(new Contact(mSearchString, mSearchString, false));
}
}
}
});
Where mSearchString
is derived from the onTextChanged
method provided with the ChipsInput library.
My onTextChanged
looks as follows
@Override
public void onChipAdded(ChipInterface chipInterface, int i) {
}
@Override
public void onChipRemoved(ChipInterface chipInterface, int i) {
}
@Override
public void onTextChanged(CharSequence charSequence) {
mSearchString = String.valueOf(charSequence);
// This adds the chip on a comma delimiter
if (mSearchString != null && mSearchString.length() > 0 && mSearchString.contains(",")) {
Log.e(TAG, mSearchString.substring(0, mSearchString.length() - 1));
String phone = mSearchString.substring(0, mSearchString.length() - 1);
chipsSearchField.addChip(new Contact(phone, phone, false));
}
}
Note that the Contact object is my object that implements the ChipInterface.
@israel-fl What a creative workaround :)
I tried to implement it but somehow the focusChangeListener is never triggered for me! Can you provide with a working example?
would be much appreciated, thanks
@majid701 I haven't touched this in quite a while but this is related to an issue in my original comment where I couldn't change the focus at all from the ChipsInput. I couldn't remove the focus, change focus, or trigger focus on anything. The text cursor was always visible in the ChipsInput no matter where I tried to put the focus, it was always ignored. As I said, it's been a while since I've touched this so I don't know if any of this has changed or been fixed but if not, I can't see how the solution would work considering my original issues. I remember I tried a similar solution, although without the extra view(because focus change wouldn't work no matter what, always stuck in the Chips) and not working.
But thanks @israel-fl, I'll keep this in mind for when I decide to pick up the project I was working again.
@joaolisboa Yeah I have noticed that as well! For some reason the focus remains fixed on the chips field! Did you found a fix for that? Any suggestions on what could be the problem and how could it be fixed? I really need to have this library working since it does exactly what I need.
thanks
@majid701 I haven't unfortunately. It'll also be a while since I can grab my project again to fix the issue but in the time I spent messing around with the library I didn't find a solution, mostly because I ended up putting too much time trying to workaround the other issues on an already limited time budget. The only workaround I could see working is either overriding the view resource(s) (if that's the cause of the issue of course, creating a resource with the same name is something I've done for some other libraries that had layout issues, just copy and make the necessary changes) or actually just digging into the code of the library to fix the issue.
@majid701, and to @joaolisboa, I noticed the requestFocus only works on some devices (All pixel phones, and some Samsung phones) but not all like the Galaxy S7 Edge. On the S7 Edge the view never loses focus.
I'm releasing to production soon and don't have time to dig into the library right now, but I came up with an even hackier solution, seriously guys it's my least favorite solution, but I need this working as quickly as possible.
On all Pixel emulators, the keyboard remains open but the view loses focus. Here the onFocusedChanged listener works perfectly as the focus goes to the next view as I showed in my earlier comment. On the Galaxy S7 edge, the keyboard closes but the view remains focused.
My solution, add a globalLayoutListener
to the ViewTreeObserver
of the main layout in the activity.
Like so:
mainContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (measureRect == null) {
measureRect = new Rect(); //you should cache this, onGlobalLayout can get called often
}
mainContent.getWindowVisibleDisplayFrame(measureRect);
// measureRect.bottom is the position above soft keypad
int keypadHeight = mainContent.getRootView().getHeight() - measureRect.bottom;
if (keypadHeight > 0) {
Log.e(TAG, "keypad opened");
// keyboard is opened
mIsKeyboardVisible = true;
} else {
Log.e(TAG, "keypad closed");
addChip();
//store keyboard state to use in onBackPress if you need to
mIsKeyboardVisible = false;
}
}
});
Where mainContent
is a RelativeLayout serving as the root of my activity.
My addChip
method is as follows:
private void addChip() {
if (mSearchString != null && mSearchString.length() > 0) {
if (mSearchString.length() >= 9) {
try {
Phonenumber.PhoneNumber numberProto = phoneNumberUtil.parse(mSearchString, "US");
// format to country:
String newPhoneNumber = phoneNumberUtil.format(numberProto, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
Log.e(TAG, "newPhone: " + newPhoneNumber);
chipsSearchField.addChip(new Contact(newPhoneNumber, newPhoneNumber, false));
} catch (NumberParseException e) {
chipsSearchField.addChip(ContextCompat.getDrawable(getApplicationContext(), R.drawable.clear_red2), mSearchString, mSearchString);
}
} else {
chipsSearchField.addChip(ContextCompat.getDrawable(getApplicationContext(), R.drawable.clear_red2), mSearchString, mSearchString);
}
}
}
Where again my ChipListener looks as follows:
@Override
public void onChipAdded(ChipInterface chipInterface, int i) {
}
@Override
public void onChipRemoved(ChipInterface chipInterface, int i) {
}
@Override
public void onTextChanged(CharSequence charSequence) {
mSearchString = String.valueOf(charSequence);
// This adds the chip on a comma delimiter
if (mSearchString != null && mSearchString.length() > 0 && mSearchString.contains(",")) {
Log.e(TAG, mSearchString.substring(0, mSearchString.length() - 1));
String phone = mSearchString.substring(0, mSearchString.length() - 1);
chipsSearchField.addChip(new Contact(phone, phone, false));
}
}
It seems to be working.
Let me know if you guys can improve the code or have a better idea of how to approach it.
Also to clarify, I currently have both the focusChanged and keyboard close observer implemented.
I am also running into the same issue, ChipsInput not triggering setOnFocusChangeListener
any solution?
@majid701, and to @joaolisboa, I noticed the requestFocus only works on some devices (All pixel phones, and some Samsung phones) but not all like the Galaxy S7 Edge. On the S7 Edge the view never loses focus.
I'm releasing to production soon and don't have time to dig into the library right now, but I came up with an even hackier solution, seriously guys it's my least favorite solution, but I need this working as quickly as possible.
On all Pixel emulators, the keyboard remains open but the view loses focus. Here the onFocusedChanged listener works perfectly as the focus goes to the next view as I showed in my earlier comment. On the Galaxy S7 edge, the keyboard closes but the view remains focused.
My solution, add a
globalLayoutListener
to theViewTreeObserver
of the main layout in the activity.Like so:
mainContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (measureRect == null) { measureRect = new Rect(); //you should cache this, onGlobalLayout can get called often } mainContent.getWindowVisibleDisplayFrame(measureRect); // measureRect.bottom is the position above soft keypad int keypadHeight = mainContent.getRootView().getHeight() - measureRect.bottom; if (keypadHeight > 0) { Log.e(TAG, "keypad opened"); // keyboard is opened mIsKeyboardVisible = true; } else { Log.e(TAG, "keypad closed"); addChip(); //store keyboard state to use in onBackPress if you need to mIsKeyboardVisible = false; } } });
Where
mainContent
is a RelativeLayout serving as the root of my activity.My
addChip
method is as follows:private void addChip() { if (mSearchString != null && mSearchString.length() > 0) { if (mSearchString.length() >= 9) { try { Phonenumber.PhoneNumber numberProto = phoneNumberUtil.parse(mSearchString, "US"); // format to country: String newPhoneNumber = phoneNumberUtil.format(numberProto, PhoneNumberUtil.PhoneNumberFormat.NATIONAL); Log.e(TAG, "newPhone: " + newPhoneNumber); chipsSearchField.addChip(new Contact(newPhoneNumber, newPhoneNumber, false)); } catch (NumberParseException e) { chipsSearchField.addChip(ContextCompat.getDrawable(getApplicationContext(), R.drawable.clear_red2), mSearchString, mSearchString); } } else { chipsSearchField.addChip(ContextCompat.getDrawable(getApplicationContext(), R.drawable.clear_red2), mSearchString, mSearchString); } } }
Where again my ChipListener looks as follows:
@Override public void onChipAdded(ChipInterface chipInterface, int i) { } @Override public void onChipRemoved(ChipInterface chipInterface, int i) { } @Override public void onTextChanged(CharSequence charSequence) { mSearchString = String.valueOf(charSequence); // This adds the chip on a comma delimiter if (mSearchString != null && mSearchString.length() > 0 && mSearchString.contains(",")) { Log.e(TAG, mSearchString.substring(0, mSearchString.length() - 1)); String phone = mSearchString.substring(0, mSearchString.length() - 1); chipsSearchField.addChip(new Contact(phone, phone, false)); } }
It seems to be working.
Let me know if you guys can improve the code or have a better idea of how to approach it.
Also to clarify, I currently have both the focusChanged and keyboard close observer implemented.
I tried your code but here I have three input fields, one is To
list and second contains Cc
and Bcc
When I am leaving from To
to Cc
I want to get the listener.
I tried with this code:
chips_input_to.setOnFocusChangeListener((view, hasFocus) -> {
if (!hasFocus) {
if (!TextUtils.isEmpty(enteredEmail)) {
enteredEmail = enteredEmail.toLowerCase().trim();
addEmailToChipView(enteredEmail, "to");
}
}
});
But it still not hitting this method.