如何自定义Gmail芯片收件人字段中使用的“芯片”自动建议机制?

时间:2014-04-03 11:15:46

标签: android autocomplete android-edittext multiautocompletetextview

背景

我一直在寻找一种具有相似外观的方法。感受Gmail收据字段,该字段允许以非常酷的方式自动填充项目:

enter image description here

构建在Android框架中并对其负责的类称为“MultiAutoCompleteTextView”。

问题

MultiAutoCompleteTextView是非常基础的,但它没有足够的样本,教程和库来了解如何在Gmail和类似设备上自定义它。

我想知道如何自定义它以处理任何类型的数据,并且我将完全控制它(例如添加,删除和获取它已自动完成的项目)。

我尝试了什么

我找到了下一步实现它的方法:

  1. 使用第三个库splitwise-TokenAutoComplete。缺点:它非常多,并且在某些设备上运行不佳。
  2. 创建我自己的方式(如图here所示)。缺点:需要很长时间,我可能需要处理与库相同的问题。
  3. 使用code of Google(找到here)。缺点:它真的不可定制。
  4. 我决定使用#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的代码。

    可悲的是,正如我所写,视图及其类对于它的使用非常紧张。

    1. 如何解除视图并使其更具可定制性?如何才能使用任何类型的数据而不仅仅是谷歌的数据?

    2. 如何输入哪些项目(成为“筹码”),还能从外部删除或添加项目?

2 个答案:

答案 0 :(得分:5)

我成功添加了添加收件人的功能。唯一要记住的是只有在视图达到它的大小之后调用它(例如如何做here):

/** 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);
}

正如我之前所写,为了获取当前在视图中的contactId列表,请使用&#34; getContactIds()&#34; 。另一种选择是:

/** 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上发布代码。

我现在唯一想念的是芯片本身的良好倾听:添加,移除和更换芯片时。对于大多数情况,我可以检测到它,但不是当用户按下退格键并移除芯片时。


编辑:还添加了监听器。现在我发现了搜索联系人的错误。它似乎搜索正常的英文字母,好像它们是电话号码。


编辑:我已经决定在GitHub上放置一个样本和一个库,here。希望尽快用更多有用的功能更新它。

我真的很高兴能为代码做出贡献。

答案 1 :(得分:1)

这个库似乎允许您配置它搜索的内容,同时还匹配Material Design外观。它似乎也基于谷歌的芯片库。我在调查类似的问题时碰巧找到了它。

https://github.com/klinker41/android-chips