一步一步学android控件(之六) —— MultiAutoCompleteTextView
今天学习的控件是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的更多相关文章
- 一步一步学android控件(之十五) —— DegitalClock & AnalogClock
原本计划DigitalClock和AnalogClock单独各一篇来写,但是想想,两个控件的作用都一样,就和在一起写一篇了. DegitalClock和AnalogClock控件主要用于显示当前时间信 ...
- 一步一步学android控件(之十六)—— CheckBox
根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...
- Android控件之MultiAutoCompleteTextView(自动匹配输入的内容)
一.功能 可支持选择多个值(在多次输入的情况下),分别用分隔符分开,并且在每个值选中的时候再次输入值时会自动去匹配,可用在发送短信,发邮件时选择联系人这种类型中 二.独特属性 android:comp ...
- 一步一步学android控件(之二十五)—— SeekBar
SeekBar扩展自ProgressBar——在ProgressBar的基础上添加了一个用户可以拖拽的thum. SeekBar.OnSeekBarChangeListener是接收SeekBar进度 ...
- Android 控件架构及View、ViewGroup的测量
附录:示例代码地址 控件在Android开发的过程中是必不可少的,无论是我们在使用系统控件还是自定义的控件.下面我们将讲解一下Android的控件架构,以及如何实现自定义控件. 1.Android控件 ...
- Android控件TextView的实现原理分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8636153 在前面一个系列的文章中,我们以窗口 ...
- Android群英传笔记——第三章:Android控件架构与自定义控件讲解
Android群英传笔记--第三章:Android控件架构与自定义控件讲解 真的很久没有更新博客了,三四天了吧,搬家干嘛的,心累,事件又很紧,抽时间把第三章大致的看完了,当然,我还是有一点View的基 ...
- Android控件GridView之仿支付宝钱包首页带有分割线的GridView九宫格的完美实现
Android控件GridView之仿支付宝钱包首页带有分割线的GridView九宫格的完美实现 2015-03-10 22:38 28419人阅读 评论(17) 收藏 举报 分类: Android ...
- [Android Pro] android控件ListView顶部或者底部也显示分割线
reference to : http://blog.csdn.net/lovexieyuan520/article/details/50846569 在默认的Android控件ListView在 ...
随机推荐
- Java HashMap 分析四篇连载
Java的HashMap非常的常用,本篇研究它的实现算法,最后希望计算出内存占用,性能的量化数据,然后得出什么时候使用HashMap,什么时候不能滥用的结论. HashMap实际上是一个数组,数组里 ...
- ActiveMQ_ActiveMQ安装与配置
ActiveMQ安装与配置 1.环境: Windows XP apache-activemq-5.2.0-bin.zip 2.安装 解压缩到apache-activemq-5.2.0-bin. ...
- Android四种Activity的加载模式
建议首先阅读下面两篇文章,这样才可以更好的理解Activity的加载模式: Android的进程,线程模型 http://www.cnblogs.com/ghj1976/archive/2011/04 ...
- .Net中常用的重要的第三方组件
RSS.NET.dll RSS.NET是一款操作RSS feeds的开源.NET类库.它为解析和编写RSS feeds提供了一个可重用的对象模型.它完全兼容RSS 0.90, 0.91, 0.92, ...
- 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 ...
- code.google.com/p/log4go 下载失败
用 glide 下载 goim 的依赖包时报错,提示: code.google.com/p/log4go 找不到,即下载失败 主要是 code.google.com 网站已关闭导致的, 有人把它 fo ...
- 【Go命令教程】12. go tool pprof
我们可以使用 go tool pprof 命令来交互式的访问概要文件的内容.命令将会分析指定的概要文件,并会根据我们的要求为我们提供高可读性的输出信息. 在 Go 语言中,我们可以通过标准库的代码包 ...
- delphi 文件查找
FindFirst 是用来寻找目标目录下的第一个文件, FindFirst函数在delphi帮助下的定义: function FindFirst(const Path: string; Attr: ...
- [Asp.net mvc]国际化
摘要 在实际项目中,经常遇到,开发的项目要提供给不同的国家使用,如果根据国家来开发不同的站点,肯定是非常耗时又耗成本的.asp.net中,提供了一种比较方便的方式,可以使用资源文件的方式,使我们的站点 ...
- 总结ASP.NET MVC视图页使用jQuery传递异步数据的几种方式
在ASP.NET MVC的视图页向控制器传递异步数据,可能是数组,JavaScript对象,json,表单数据,等等. 关于数据,JavaScript对象有时候和json长得一模一样,有么有? var ...