如何自定义"芯片"自动提示机制,对使用Gmail的收件人场? [英] How to customize the "chips" auto-suggesting mechanism, as used on Gmail's recipients field?
问题描述
背景
我已经寻找一种方式也有类似的外观和放大器;感觉Gmail的receipients领域,允许自动灌装项目的一个非常酷的方式:
这是内置在Android框架和类是负责这就是所谓的<一个href="http://developer.android.com/reference/android/widget/MultiAutoCompleteTextView.html">MultiAutoCompleteTextView"
问题
在MultiAutoCompleteTextView是基本相当,但它并没有保持足够的样本,教程和图书馆去知道如何像Gmail和喜欢定制。
我想知道如何进行定制,以处理任何类型的数据,我将有充分的控制权(例如添加,删除和获取,它已经自动完成的项目)。
我已经试过
我发现实现这一目标的一个可能的方式:
- 使用第三个库像<一个href="https://github.com/splitwise/TokenAutoComplete">splitwise-TokenAutoComplete.缺点:这是非常错误且不在某些设备正常工作
- 创建我自己的方式(如<一个href="http://stackoverflow.com/questions/19676347/setting-multiple-custom-elements-to-multiautocompletetextview-android/">here).缺点:需要很长的时间,我可能会需要处理同样的问题库
- 使用<一个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。
可悲的是,我已经写了,认为其课程十分紧张到它的用法。
-
我怎样才能取消夫妇的观点,并使其更可自定义的?我怎样才能使它使用任何类型的数据,而不是仅仅是谷歌已经做了什么?
的
-
我如何获得了进入该项目(即变成了芯片),也可以删除或从外部添加项目?
我已经成功地将添加收件人的功能。唯一要记住的是调用它后,才认为得到了该怎么办呢它的大小(例如 这里 ):
/ **添加一个收件人的看法。注意,当视图已经确定其大小*它应该被称为/
公共无效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; DrawableRecipientChip&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:
- use a third library like splitwise-TokenAutoComplete. the downside: it's very buggy and doesn't work well on some devices.
- 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.
- 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.
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?
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屋!