Как настроить механизм автоматического предложения "фишек", используемый в поле получателей Gmail?
Фон
Я искал способ выглядеть и чувствовать себя похожим на поле Gmail receipients, которое позволяет автоматически заполнять элементы действительно классным способом:
Класс, который встроен в платформу 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?
-
Как я могу узнать, какие элементы были введены (которые стали "фишками"), а также иметь возможность удалять или добавлять элементы из снаружи?
2 ответа:
Мне удалось добавить функциональность добавления получателя. Единственное, что нужно запомнить, это вызвать его только после того, как вид получил свой размер (пример того, как это сделать здесь) :
/** 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); }
И, как я уже писал ранее, для получения списка contactIds, которые в настоящее время находятся внутри представления, используйте "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.
Единственное, чего мне сейчас не хватает-это хороший слушатель к самим чипам : когда чип добавляется, удаляется и заменяется. в большинстве случаев я могу обнаружить его, но не тогда, когда пользователь нажимает backspace и удаляет чип.
EDIT: также добавлен слушатель. теперь я нашел ошибку в поиске контактов. похоже, что он ищет обычные английские буквы, как если бы они были телефонными номерами.
EDIT: я решил поместить образец и библиотеку на GitHub, здесь . Надеюсь обновить его с более полезным особенности скоро.
Я был бы очень рад любому вкладу в этот код.