Подтвердить что ты не робот

Как настроить механизм автоматического предложения "чипов", используемый в поле получателей 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?

  • Как мне получить, какие элементы были введены (которые стали "фишками" ), а также удалять или добавлять элементы извне?

4b9b3361

Ответ 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