背景
我一直在寻找一种与 Gmail 收件人字段具有相似外观和感觉的方法,它允许以非常酷的方式自动填充项目:
内置于 Android 框架中并负责此操作的类称为“MultiAutoCompleteTextView”。
问题
MultiAutoCompleteTextView 非常基础,但它没有足够的示例、教程和库来了解如何像在 Gmail 等上一样对其进行自定义。
我想知道如何自定义它来处理任何类型的数据,并且我将完全控制它(例如添加、删除和获取它自动完成的项目)。
我尝试过的
我找到了实现它的下一个可能方法:
- 使用第三个库,例如 splitwise-TokenAutoComplete .缺点:它有很多错误,在某些设备上运行不佳。
- 创建我自己的方式(如图 here 所示)。缺点:需要很长时间,我可能需要处理与图书馆相同的问题。
- 使用code of Google (找到 here )。缺点:它确实不可定制。
我决定使用 #3(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;
}
它工作正常,但我在添加和删除项目时遇到困难。
我认为获取item是通过调用“getContactIds”来使用的,但是关于修改chips中的item,这很难找到。
例如,我尝试向“submitItemAtPosition”添加一个类似的功能,这似乎添加了一个从适配器中找到的新实体。它确实添加了,但联系人的显示名称并未显示在芯片本身上。
问题
想了很多,还是决定用Google的code。
遗憾的是,正如我所写的, View 及其类对它的使用非常严格。
如何解耦 View 并使其更易于定制?我怎样才能让它使用任何类型的数据,而不仅仅是谷歌所做的?
如何获取输入了哪些项目(成为“筹码”),以及如何从外部删除或添加项目?
最佳答案
我已经成功添加了添加收件人的功能。唯一要记住的是只有在 View 达到其大小后才调用它(如何做的示例 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);
}
正如我之前所写,要获取当前在 View 中的 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 上。
我现在唯一想念的是芯片本身的良好倾听者:添加、移除和更换芯片时。在大多数情况下,我可以检测到它,但当用户按下退格键并移除筹码时,我无法检测到。
编辑:还添加了监听器。现在我在搜索联系人时发现了一个错误。它似乎像搜索电话号码一样搜索正常的英文字母。
编辑:我决定将示例和库放在 GitHub 上,here .希望尽快用更多有用的功能更新它。
如果对代码做出任何贡献,我真的很高兴。
关于android - 如何自定义 Gmail 收件人字段中使用的 "chips"自动建议机制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22835888/