今天学习的控件是MultiAutoCompleteTextView 。 提到MultiAutoCompleteTextView 我们就自然而然地想到AutoCompleteTextView ,就想知道他们之间到底有什么区别。在讲他们区别之前呢先来看看下面两张图片:

                               

(图1)AutoCompleteTextView                           (图2)MultiAutoCompleteTextView

这两张图片中使用的都是同样的Adapter , 然而在图1中输入图2中的内容时却得不到任何内容,为什么?

先从他们的关系上说说, MultiAutoCompleteTextView 继承自AutoCompleteTextView(废话 ... 囧) , 在使用上多了一个Tokenizer —— 在图2中,这个Tokenizer就是符号 ‘ , ’ ,当遇到这个符号时会根据光标的位置计算当前关注的信息。如:如果光标在  d  的位置,则 ‘ , ’之前的字串有效;如果光标在 g 位置,则 ‘ , ’ 后面的字串有效;另外如果光标前后都有符号‘ , ’ , 则在两个 ‘ , ’ 中的内容有效。对于这段解释,下面的代码获取更具说服力:

public static class SelfDedineTokenizer implements Tokenizer {

        private char mTokenizer = ',';

        public SelfDedineTokenizer() {
} public SelfDedineTokenizer(char token) {
mTokenizer = token;
} public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == mTokenizer) {
return i;
} else {
i++;
}
}
return len; } public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != mTokenizer) {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
} public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == mTokenizer) {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text
+ String.valueOf(mTokenizer));
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + String.valueOf(mTokenizer);
}
}
} public void setToken(char token) {
mTokenizer = token;
} public char getToken() {
return mTokenizer;
}
}

这段代码是自定义的Tokenizer , 默认使用 ‘ , ’ 作为分隔符, 若想用其他的符号替换 ‘ , ’ 使用setToken方法即可。

废话也说了那么多了,现在说说今天要做的事情

1、使用异步调用方法(Executors)加载MultiAutoCompleteTextView 中 Adapter 需要的数据(数据跟AutoCompleteTextView一样,有疑问的可参见 点击一步一步学android控件(之五) —— AutoCompleteTextView

2、在MultiAutoCompleteTextView中使用自定义的Tokenizer而不是默认的Tokenizer。

下面就来实现这些功能,老规矩先准备资源文件

1、 创建布局文件 multi_auto_complete_textview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <MultiAutoCompleteTextView
android:id="@+id/show_multi_complete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginTop="20dp" /> </LinearLayout>

2、创建activity ——WidgetMultiAutoCompleteActivity.java

package com.xy.zt.selfdefinewieget;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.widget.ArrayAdapter;
import android.widget.MultiAutoCompleteTextView;
import android.widget.MultiAutoCompleteTextView.Tokenizer; public class WidgetMultiAutoCompleteActivity extends Activity { public static final String[] DEFAULT_DATAS = new String[] { "China",
"chengdu", "xueyu", "ting", "baba", "mama", "meimei" };
public static final int MSG_RECEIVE_TASK_DATA = 1024; private ExecutorService mExecutor;
private ArrayAdapter<String> mMultiAdapter;
private MultiAutoCompleteTextView mShowMulti;
// private CommaTokenizer mComma = new CommaTokenizer();
private Future<List<String>> mListFileTask; private static final Callable<List<String>> LIST_FILES = new Callable<List<String>>() {
public List<String> call() throws Exception {
File rootDir = Environment.getRootDirectory();
LinkedList<File> queue = new LinkedList<File>();
ArrayList<String> result = new ArrayList<String>(100);
queue.offer(rootDir);
File tmpFile, tmpDirAllFile[];
while ((tmpFile = queue.poll()) != null) {
if (tmpFile.isDirectory()) {
tmpDirAllFile = tmpFile.listFiles();
if (tmpDirAllFile != null) {
for (File f : tmpDirAllFile) {
queue.offer(f);
}
}
} else {
result.add(tmpFile.getName());
}
}
return result;
} }; Handler mHandler = new Handler() { @SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RECEIVE_TASK_DATA:
List<String> datas;
try {
datas = (List<String>) msg.obj;
} catch (ClassCastException e) {
datas = useDefaultData();
} mShowMulti.setEnabled(true);
mMultiAdapter = new ArrayAdapter<String>(
WidgetMultiAutoCompleteActivity.this,
R.layout.auto_complete_item, R.id.auto_item_file_name,
datas);
mShowMulti.setAdapter(mMultiAdapter);
break;
}
;
} }; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.multi_auto_complete_textview);
init();
mExecutor = Executors.newCachedThreadPool();
mListFileTask = mExecutor.submit(LIST_FILES);
mExecutor.submit(new Runnable() {
@SuppressLint("HandlerLeak")
public void run() {
List<String> datas;
try {
datas = mListFileTask.get();
} catch (InterruptedException e) {
datas = useDefaultData();
} catch (ExecutionException e) {
datas = useDefaultData();
}
Message msg = mHandler.obtainMessage(MSG_RECEIVE_TASK_DATA);
msg.obj = datas;
mHandler.sendMessage(msg);
} }); } void init() {
mShowMulti = (MultiAutoCompleteTextView) findViewById(R.id.show_multi_complete);
mShowMulti.setEnabled(false);
mShowMulti.setTokenizer(mCustomerToken);
mShowMulti.setThreshold(1);
} private List<String> useDefaultData() {
List<String> datas = new ArrayList<String>();
for (String s : DEFAULT_DATAS) {
datas.add(s);
}
return datas;
} @Override
protected void onDestroy() {
super.onDestroy();
mExecutor.shutdown();
} SelfDedineTokenizer mCustomerToken = new SelfDedineTokenizer(';'); public static class SelfDedineTokenizer implements Tokenizer { private char mTokenizer = ','; public SelfDedineTokenizer() {
} public SelfDedineTokenizer(char token) {
mTokenizer = token;
} public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == mTokenizer) {
return i;
} else {
i++;
}
}
return len; } public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != mTokenizer) {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
} public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == mTokenizer) {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text
+ String.valueOf(mTokenizer));
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + String.valueOf(mTokenizer);
}
}
} public void setToken(char token) {
mTokenizer = token;
} public char getToken() {
return mTokenizer;
}
}
}

今天主要的内容就在这个文件中,先来看看

 private static final Callable<List<String>> LIST_FILES = new Callable<List<String>>()

Callable接口类似于Runnable,只是他是有返回结果的Runnable , 在他的call方法中做搜索系统文件的工作。  在onCreat函数中有下面代码:

mExecutor = Executors.newCachedThreadPool();
mListFileTask = mExecutor.submit(LIST_FILES);

这段代码第一句创建了一个线程池,第二句将ListFILES提交到线程池进行处理。接下来的代码:

mExecutor.submit(new Runnable() {
@SuppressLint("HandlerLeak")
public void run() {
List<String> datas;
try {
datas = mListFileTask.get();
} catch (InterruptedException e) {
datas = useDefaultData();
} catch (ExecutionException e) {
datas = useDefaultData();
}
Message msg = mHandler.obtainMessage(MSG_RECEIVE_TASK_DATA);
msg.obj = datas;
mHandler.sendMessage(msg);
} });

这段代码将一个Runnable提交到线程池执行,mListFileTask.get(); 这句在Callable中的call函数没有执行完之前一直处于阻塞状态(不可以放到主线程中),得到数据后发送消息更新UI。

在init函数中有这么一句:

mShowMulti.setTokenizer(mCustomerToken);

表示使用的是自定义的Tokenizer,他的定义如下

SelfDedineTokenizer mCustomerToken = new SelfDedineTokenizer(';');

这样看到的效果跟图二的就有点不同了哦 ^_^......

3、 完善真个工程,下面滴内容也是不可少滴。也写了几个控件了,看看现在ViewData.java中的内容

package com.xy.zt.selfdefinewieget.data;

import java.util.ArrayList;

final public class ViewData {

    public final static ArrayList<ViewData> View_Datas = new ArrayList<ViewData>();

    public static final int TEXT_VIEW_ID = 90000;
public static final String TEXT_VIEW_NAME = "TextView"; public static final int BUTTON_ID = TEXT_VIEW_ID + 1;
public static final String BUTTON_NAME = "Button"; public static final int EDIT_TEXT_ID = BUTTON_ID + 1;
public static final String EDIT_TEXT_NAME = "EditText"; public static final int AUTO_COMPLETE_TEXTVIEW_ID = EDIT_TEXT_ID + 1;
public static final String AUTO_COMPLETE_TEXTVIEW_NAME = "AutoCompleteTextView"; public static final int MULTI_AUTO_COMPLETE_TEXTVIEW_ID = AUTO_COMPLETE_TEXTVIEW_ID + 1;
public static final String MULTI_AUTO_COMPLETE_TEXTVIEW_NAME = "MultiAutoCompleteTextView"; private static final ViewData mTextView = new ViewData(TEXT_VIEW_NAME,
TEXT_VIEW_ID);
private static final ViewData mButton = new ViewData(BUTTON_NAME, BUTTON_ID);
private static final ViewData mEditText = new ViewData(EDIT_TEXT_NAME,
EDIT_TEXT_ID);
private static final ViewData mAutoCompleteTextView = new ViewData(
AUTO_COMPLETE_TEXTVIEW_NAME, AUTO_COMPLETE_TEXTVIEW_ID);
private static final ViewData mMultiAutoCompleteTextView = new ViewData(
MULTI_AUTO_COMPLETE_TEXTVIEW_NAME, MULTI_AUTO_COMPLETE_TEXTVIEW_ID); public final String mViewName;
public final int mViewId; private ViewData(String name, int id) {
mViewName = name;
mViewId = id;
} static {
View_Datas.add(mTextView);
View_Datas.add(mButton);
View_Datas.add(mEditText);
View_Datas.add(mAutoCompleteTextView);
View_Datas.add(mMultiAutoCompleteTextView);
}
}

最后在WidgetsAdapter的handleItemClicked函数中加入如下内容:

case ViewData.MULTI_AUTO_COMPLETE_TEXTVIEW_ID:
intent.setClass(mContext, WidgetMultiAutoCompleteActivity.class);
mContext.startActivity(intent);
break;

handleItemClicked 最新内容如下:

private void handleItemClicked(int action) {
Intent intent = new Intent();
switch (action) {
case ViewData.TEXT_VIEW_ID:
intent.setClass(mContext, WidgetTextView.class);
mContext.startActivity(intent);
break;
case ViewData.BUTTON_ID:
intent.setClass(mContext, WidgetButtonActivity.class);
mContext.startActivity(intent);
break;
case ViewData.EDIT_TEXT_ID:
intent.setClass(mContext, WidgetEditTextActivity.class);
mContext.startActivity(intent);
break;
case ViewData.AUTO_COMPLETE_TEXTVIEW_ID:
intent.setClass(mContext, WidgetAutoCompleteActivity.class);
mContext.startActivity(intent);
break;
case ViewData.MULTI_AUTO_COMPLETE_TEXTVIEW_ID:
intent.setClass(mContext, WidgetMultiAutoCompleteActivity.class);
mContext.startActivity(intent);
break;
}
}

MultiAutoCompleteTextView 就介绍到这里了,下一个控件 Toast 。

一步一步学android控件(之六) —— MultiAutoCompleteTextView的更多相关文章

  1. 一步一步学android控件(之十五) —— DegitalClock & AnalogClock

    原本计划DigitalClock和AnalogClock单独各一篇来写,但是想想,两个控件的作用都一样,就和在一起写一篇了. DegitalClock和AnalogClock控件主要用于显示当前时间信 ...

  2. 一步一步学android控件(之十六)—— CheckBox

    根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...

  3. Android控件之MultiAutoCompleteTextView(自动匹配输入的内容)

    一.功能 可支持选择多个值(在多次输入的情况下),分别用分隔符分开,并且在每个值选中的时候再次输入值时会自动去匹配,可用在发送短信,发邮件时选择联系人这种类型中 二.独特属性 android:comp ...

  4. 一步一步学android控件(之二十五)—— SeekBar

    SeekBar扩展自ProgressBar——在ProgressBar的基础上添加了一个用户可以拖拽的thum. SeekBar.OnSeekBarChangeListener是接收SeekBar进度 ...

  5. Android 控件架构及View、ViewGroup的测量

    附录:示例代码地址 控件在Android开发的过程中是必不可少的,无论是我们在使用系统控件还是自定义的控件.下面我们将讲解一下Android的控件架构,以及如何实现自定义控件. 1.Android控件 ...

  6. Android控件TextView的实现原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8636153 在前面一个系列的文章中,我们以窗口 ...

  7. Android群英传笔记——第三章:Android控件架构与自定义控件讲解

    Android群英传笔记--第三章:Android控件架构与自定义控件讲解 真的很久没有更新博客了,三四天了吧,搬家干嘛的,心累,事件又很紧,抽时间把第三章大致的看完了,当然,我还是有一点View的基 ...

  8. Android控件GridView之仿支付宝钱包首页带有分割线的GridView九宫格的完美实现

    Android控件GridView之仿支付宝钱包首页带有分割线的GridView九宫格的完美实现 2015-03-10 22:38 28419人阅读 评论(17) 收藏 举报  分类: Android ...

  9. [Android Pro] android控件ListView顶部或者底部也显示分割线

    reference to  :  http://blog.csdn.net/lovexieyuan520/article/details/50846569 在默认的Android控件ListView在 ...

随机推荐

  1. Java HashMap 分析四篇连载

     Java的HashMap非常的常用,本篇研究它的实现算法,最后希望计算出内存占用,性能的量化数据,然后得出什么时候使用HashMap,什么时候不能滥用的结论. HashMap实际上是一个数组,数组里 ...

  2. ActiveMQ_ActiveMQ安装与配置

    ActiveMQ安装与配置   1.环境: Windows XP apache-activemq-5.2.0-bin.zip   2.安装 解压缩到apache-activemq-5.2.0-bin. ...

  3. Android四种Activity的加载模式

    建议首先阅读下面两篇文章,这样才可以更好的理解Activity的加载模式: Android的进程,线程模型 http://www.cnblogs.com/ghj1976/archive/2011/04 ...

  4. .Net中常用的重要的第三方组件

    RSS.NET.dll RSS.NET是一款操作RSS feeds的开源.NET类库.它为解析和编写RSS feeds提供了一个可重用的对象模型.它完全兼容RSS 0.90, 0.91, 0.92, ...

  5. OpenOCD 0.9.0 release

    OpenOCD 0.9.0 release May 18th, 2015 I’m happy to announce the release of OpenOCD version 0.9.0, fin ...

  6. code.google.com/p/log4go 下载失败

    用 glide 下载 goim 的依赖包时报错,提示: code.google.com/p/log4go 找不到,即下载失败 主要是 code.google.com 网站已关闭导致的, 有人把它 fo ...

  7. 【Go命令教程】12. go tool pprof

    我们可以使用 go tool pprof 命令来交互式的访问概要文件的内容.命令将会分析指定的概要文件,并会根据我们的要求为我们提供高可读性的输出信息. 在 Go 语言中,我们可以通过标准库的代码包 ...

  8. delphi 文件查找

    FindFirst  是用来寻找目标目录下的第一个文件, FindFirst函数在delphi帮助下的定义: function FindFirst(const Path: string; Attr: ...

  9. [Asp.net mvc]国际化

    摘要 在实际项目中,经常遇到,开发的项目要提供给不同的国家使用,如果根据国家来开发不同的站点,肯定是非常耗时又耗成本的.asp.net中,提供了一种比较方便的方式,可以使用资源文件的方式,使我们的站点 ...

  10. 总结ASP.NET MVC视图页使用jQuery传递异步数据的几种方式

    在ASP.NET MVC的视图页向控制器传递异步数据,可能是数组,JavaScript对象,json,表单数据,等等. 关于数据,JavaScript对象有时候和json长得一模一样,有么有? var ...