如何自定义"芯片"自动提示机制,对使用Gmail的收件人场? [英] How to customize the "chips" auto-suggesting mechanism, as used on Gmail's recipients field?

查看:196
本文介绍了如何自定义"芯片"自动提示机制,对使用Gmail的收件人场?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

我已经寻找一种方式也有类似的外观和放大器;感觉Gmail的receipients领域,允许自动灌装项目的一个非常酷的方式:

这是内置在Android框架和类是负责这就是所谓的<一个href="http://developer.android.com/reference/android/widget/MultiAutoCompleteTextView.html">MultiAutoCompleteTextView"

问题

在MultiAutoCompleteTextView是基本相当,但它并没有保持足够的样本,教程和图书馆去知道如​​何像Gmail和喜欢定制。

我想知道如何进行定制,以处理任何类型的数据,我将有充分的控制权(例如添加,删除和获取,它已经自动完成的项目)。

我已经试过

我发现实现这一目标的一个可能的方式:

  1. 使用第三个库像<一个href="https://github.com/splitwise/TokenAutoComplete">splitwise-TokenAutoComplete.缺点:这是非常错误且不在某些设备正常工作
  2. 创建我自己的方式(如<一个href="http://stackoverflow.com/questions/19676347/setting-multiple-custom-elements-to-multiautocompletetextview-android/">here).缺点:需要很长的时间,我可能会需要处理同样的问题库
  3. 使用<一个href="https://android.googlesource.com/platform/frameworks/ex/+/android-sdk-support_r11">$c$c谷歌的 (发现 此处 )。缺点:这真的不是定制

我已经决定使用#3(谷歌的筹码库)。

目前的code获取联系人对谷歌的库中使用的清单:

 公开名单&LT; RecipientEntry&GT; doQuery(){
    最后光标光标= mContentResolver.query(mQuery.getContentUri(),mQuery.getProjection(),NULL,NULL,NULL);
    最后的LinkedHashMap&LT;长,列表和LT; RecipientEntry&GT;&GT; entryMap =新的LinkedHashMap&LT;长,列表和LT; RecipientEntry&GT;&GT;();
    最后的名单,其中,RecipientEntry&GT; nonAggregatedEntries =新的ArrayList&LT; RecipientEntry&GT;();
    决胜盘&LT;字符串&GT; existingDestinations =新的HashSet&LT;字符串&GT;();
    而(cursor.moveToNext())
        putOneEntry(新TemporaryEntry(光标,假/ * isGalContact * /),真实,entryMap,nonAggregatedEntries,
                existingDestinations);
    cursor.close();
    最后的名单,其中,RecipientEntry&GT;项=新的ArrayList&LT; RecipientEntry&GT;();
    {
        对于(最终为Map.Entry&LT;长,列表和LT; RecipientEntry&GT;&GT; mapEntry:entryMap.entrySet()){
            最后的名单,其中,RecipientEntry&GT; entryList = mapEntry.getValue();
            对于(最终RecipientEntry recipientEntry:entryList)
                entries.add(recipientEntry);
        }
        对于(最终RecipientEntry项:nonAggregatedEntries)
            entries.add(入口);
    }
    返回条目;
}
 

它工作正常,但我有困难的添加项和删除它们。

我觉得获得物品时,通过调用getContactIds,但对芯片内修改的项目,这是非常有问题的发现。

例如,我试图加入类似的功能为submitItemAtPosition,这似乎增加发现从适配器一个新的实体。它确实增加,但接触的显示名不芯片本身上显示

问题

很多的想法后,我决定使用谷歌的code。

可悲的是,我已经写了,认为其课程十分紧张到它的用法。

  1. 我怎样才能取消夫妇的观点,并使其更可自定义的?我怎样才能使它使用任何类型的数据,而不是仅仅是谷歌已经做了什么?

  2. 我如何获得了进入该项目(即变成了芯片),也可以删除或从外部添加项目?

解决方案

我已经成功地将添加收件人的功能。唯一要记住的是调用它后,才认为得到了该怎么办呢它的大小(例如 这里 ):

  / **添加一个收件人的看法。注意,当视图已经确定其大小*它应该被称为/
公共无效addRecipient(最终RecipientEntry进入){
    如果(入口== NULL)
        返回;
    clearComposingText();

    最终诠释结束= getSelectionEnd();
    最终诠释开始= mTokenizer.findTokenStart(gettext的(),结束);

    最后编辑编辑=的getText();
    QwertyKeyListener.markAsReplaced(可编辑,开始,结束,);
    最后的CharSequence芯片= createChip(入口,假);
    如果(芯片= NULL和放大器;!&安培;开始&gt; = 0&功放;&安培;末&GT; = 0){
        editable.replace(开始,结束芯片);
    }
    sanitizeBetween();
}

私人无效submitItemAtPosition(最终诠释位置){
    最后RecipientEntry进入= createValidatedEntry(getAdapter()的getItem(位置)。);
    如果(入口== NULL)
        返回;
    addRecipient(入口);
}
 

和,删除:

  / **从视图中删除*芯片的收件人/
公共无效removeRecipient(最终RecipientEntry进入){
    最终DrawableRecipientChip []芯片= getSpannable()。getSpans(0,的getText()。长度(),
            DrawableRecipientChip.class);
    最后的名单,其中,DrawableRecipientChip&GT; chipsToRemove =新的ArrayList&LT; D​​rawableRecipientChip&GT;();
    对于(最终DrawableRecipientChip芯片:芯片)
        如果(chip.getDataId()== entry.getDataId())
            chipsToRemove.add(芯片);
    对于(最终DrawableRecipientChip芯片:chipsToRemove)
        removeChip(芯片);
}
 

和为我写之前,获取contactIds的是当前视图中的列表,请使用getContactIds()。另一种选择是:

  / **返回所有的芯片项目的集合。关键是接触的id,并且该值是收件人本身* /
公共地图&LT;长,RecipientEntry&GT; getChosenRecipients(){
    最终的地图&LT;长,RecipientEntry&GT;结果=新的HashMap&LT;长,RecipientEntry&GT;();
    最后DrawableRecipientChip []芯片= getSortedRecipients();
    如果(筹!= NULL)
        对于(最终DrawableRecipientChip芯片:芯片){
            //如果(结果)。
            最终长的ContactID = chip.getContactId();
            如果(!result.containsKey(的ContactID))
                result.put(的ContactID,chip.getEntry());
        }
    返回结果;
}
 

也许我应该张贴了code Github上。

我唯一现在怀念的是一个很好的倾听者,以芯片本身:当芯片被添加,删除和替换。对于大多数的情况下,我可以检测到它,但不是当用户presses退格键和删除一个芯片


编辑:还增加了听众。现在我已经找到了一个错误,在搜索联系人。它似乎搜索正常英文字母,就像它们是电话号码。


编辑:我已经决定把样本,并在GitHub上图书馆, 这里 。希望能尽快与更有用的功能更新。

我真的会高兴到code的任何贡献。

Background

I've searched for a way to have a similar look & feel to the Gmail receipients field, which allows auto-filling of items in a really cool way:

The class that is built into the Android framework and is responsible for this is called "MultiAutoCompleteTextView" .

The problem

the MultiAutoCompleteTextView is quite basic, yet it doesn't hold enough samples, tutorials and libraries to get to know how to customize it like on Gmail and the likes.

I would like to know how to customize it to handle any kind of data, and that I will have full control over it (for example adding, deleting and getting the items that it has auto-completed).

What I've tried

I've found the next possible ways to achieve it:

  1. use a third library like splitwise-TokenAutoComplete. the downside: it's very buggy and doesn't work well on some devices.
  2. create my own way (as shown here). the downside: will take a long time and I will probably need to handle the same problems as of the library.
  3. use the code of Google (found here). The downside: it's really not customizable.

I've decided to use #3 (Google's chips library).

Currently the code for getting the list of contacts used on Google's library:

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;
}

It works fine, but I'm having difficulties adding items and deleting them.

I think that getting the items is used by calling "getContactIds" , but about modifying the items within the chips, that's very problematic to find.

For example, I've tried to add a similar function to "submitItemAtPosition" , which seems to add a new entity found from the adapter. It does add, but the display-name of the contact isn't shown on the chip itself.

The question

After a lot of thoughts, I decided to use Google's code.

Sadly, as I've written, the view and its classes are very tight to the usage of it.

  1. How can I de-couple the view and make it much more customizable? How can I make it use any type of data instead of just what Google has done?

  2. How do I get which items were entered (that became "chips"), and also be able to remove or add items from outside?

解决方案

I've succeeded adding the functionality of adding a recipient. The only thing to remember is to call it only after the view got its size (example of how to do it 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);
}

And, for deletion:

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

and as I've written before, for getting the list of contactIds that are currently inside the view, use "getContactIds()" . Another alternative is:

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

Maybe I should post the code on Github.

The only thing I miss now is a good listener to the chips themselves : when a chip is added, removed and replaced. for most of the cases I can detect it, but not when the user presses backspace and removes a chip.


EDIT: also added the listener. now I've found a bug in searching of contacts. it seems to search the normal English letters as if they were phone numbers.


EDIT: I've decided to put a sample and a library on GitHub, here . Hope to update it with more useful features soon.

I would really be happy for any contribution to the code.

这篇关于如何自定义&QUOT;芯片&QUOT;自动提示机制,对使用Gmail的收件人场?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆