Как настроить механизм автоматического предложения "чипов", используемый в поле получателей Gmail?
Фон
Я искал способ иметь похожий внешний вид в поле получателей Gmail, что позволяет автоматически заполнять элементы по-настоящему круто:
![enter image description here]()
Класс, встроенный в платформу Android и ответственный за это, называется " MultiAutoCompleteTextView".
Проблема
MultiAutoCompleteTextView довольно простой, но он не содержит достаточного количества образцов, учебников и библиотек, чтобы узнать, как его настроить, как в Gmail и т.д.
Я хотел бы знать, как настроить его для обработки любых данных, и что у меня будет полный контроль над ним (например, добавление, удаление и получение элементов, которые он автоматически завершил).
Что я пробовал
Я нашел следующие возможные способы его достижения:
- используйте третью библиотеку, например splitwise-TokenAutoComplete. недостаток: он очень глючит и не работает на некоторых устройствах.
- создайте свой собственный путь (как показано здесь). недостаток: займет много времени, и мне, вероятно, придется решать те же проблемы, что и в библиотеке.
- используйте код Google (найдено здесь). Недостаток: он действительно не настраиваемый.
Я решил использовать # 3 (библиотека чипов Google).
В настоящее время код для получения списка контактов, используемых в библиотеке Google:
public List<RecipientEntry> doQuery() {
final Cursor cursor = mContentResolver.query(mQuery.getContentUri(), mQuery.getProjection(), null, null, null);
final LinkedHashMap<Long, List<RecipientEntry>> entryMap = new LinkedHashMap<Long, List<RecipientEntry>>();
final List<RecipientEntry> nonAggregatedEntries = new ArrayList<RecipientEntry>();
final Set<String> existingDestinations = new HashSet<String>();
while (cursor.moveToNext())
putOneEntry(new TemporaryEntry(cursor, false /* isGalContact */), true, entryMap, nonAggregatedEntries,
existingDestinations);
cursor.close();
final List<RecipientEntry> entries = new ArrayList<RecipientEntry>();
{
for (final Map.Entry<Long, List<RecipientEntry>> mapEntry : entryMap.entrySet()) {
final List<RecipientEntry> entryList = mapEntry.getValue();
for (final RecipientEntry recipientEntry : entryList)
entries.add(recipientEntry);
}
for (final RecipientEntry entry : nonAggregatedEntries)
entries.add(entry);
}
return entries;
}
Он отлично работает, но у меня возникают трудности с добавлением элементов и их удалением.
Я думаю, что получение элементов используется при вызове "getContactIds", но об изменении элементов внутри фишек, что очень проблематично для поиска.
Например, я попытался добавить подобную функцию в "submitItemAtPosition", которая, кажется, добавляет новый объект, найденный из адаптера. Он добавляет, но отображаемое имя контакта не отображается на самом чипе.
Вопрос
После многих мыслей я решил использовать код Google.
К сожалению, как я уже писал, представление и его классы очень сильно зависят от его использования.
-
Как я могу отключить просмотр и сделать его более настраиваемым? Как я могу использовать данные любого типа вместо того, что сделал Google?
-
Как мне получить, какие элементы были введены (которые стали "фишками" ), а также удалять или добавлять элементы извне?
Ответы
Ответ 1
Мне удалось добавить функциональность добавления получателя. Единственное, что нужно помнить, - называть его только после того, как представление получило его размер (пример того, как это сделать здесь):
/** adds a recipient to the view. note that it should be called when the view has determined its size */
public void addRecipient(final RecipientEntry entry) {
if (entry == null)
return;
clearComposingText();
final int end = getSelectionEnd();
final int start = mTokenizer.findTokenStart(getText(), end);
final Editable editable = getText();
QwertyKeyListener.markAsReplaced(editable, start, end, "");
final CharSequence chip = createChip(entry, false);
if (chip != null && start >= 0 && end >= 0) {
editable.replace(start, end, chip);
}
sanitizeBetween();
}
private void submitItemAtPosition(final int position) {
final RecipientEntry entry = createValidatedEntry(getAdapter().getItem(position));
if (entry == null)
return;
addRecipient(entry);
}
И, для удаления:
/** removes a chip of a recipient from the view */
public void removeRecipient(final RecipientEntry entry) {
final DrawableRecipientChip[] chips = getSpannable().getSpans(0, getText().length(),
DrawableRecipientChip.class);
final List<DrawableRecipientChip> chipsToRemove = new ArrayList<DrawableRecipientChip>();
for (final DrawableRecipientChip chip : chips)
if (chip.getDataId() == entry.getDataId())
chipsToRemove.add(chip);
for (final DrawableRecipientChip chip : chipsToRemove)
removeChip(chip);
}
и, как я писал ранее, для получения списка контактов, которые в настоящее время находятся внутри представления, используйте "getContactIds()". Другой вариант:
/** returns a collection of all of the chips' items. key is the contact id, and the value is the recipient itself */
public Map<Long, RecipientEntry> getChosenRecipients() {
final Map<Long, RecipientEntry> result = new HashMap<Long, RecipientEntry>();
final DrawableRecipientChip[] chips = getSortedRecipients();
if (chips != null)
for (final DrawableRecipientChip chip : chips) {
// if(result.)
final long contactId = chip.getContactId();
if (!result.containsKey(contactId))
result.put(contactId, chip.getEntry());
}
return result;
}
Может быть, я должен опубликовать код на Github.
Единственное, чего я пропустил сейчас, это хороший слушатель для самих чипов: когда чип добавляется, удаляется и заменяется. для большинства случаев я могу его обнаружить, но не тогда, когда пользователь нажимает на обратное пространство и удаляет чип.
EDIT: также добавлен слушатель. теперь я нашел ошибку в поиске контактов. он, кажется, ищет обычные английские буквы, как если бы они были номерами телефонов.
EDIT: я решил поместить образец и библиотеку в GitHub, здесь. Надеемся обновить его с помощью более полезных функций.
Я действительно был бы рад за любой вклад в код.
Ответ 2
Эта библиотека, похоже, позволяет вам настроить то, что она ищет, а также сопоставляя внешний вид Material Design. Он также, похоже, основан на библиотеке чипов Google. Мне удалось найти его при исследовании аналогичной проблемы.
https://github.com/klinker41/android-chips