`

AutoCompleteTextView

阅读更多

AutoCompleteTextView

 

AutoCompleteTextView具有输入提示的功能,但是它的这种提示不适合对股票列表的过滤,如果你玩过股票软件,就会知道只要输入股票名称的首字母或股票代码就会出现符合匹配的股票,这种过滤怎么实现呢?
还有个问题,汉字具有多音字,如何实现多音字的匹配,比如“长江证券”,无论你输入“cjzq”或者“zjzq”都会匹配到它,这都是需要解决的问题!
匹配的关键在于重写BaseAdapter,让它实现Filterable接口,重写其中的getFilter(),如果你参照ArrayAdaper源码的话,写起来就会容易很多,事实上我就是这么做的,^o^
下面看一下源码:

Java代码  收藏代码
  1. package  com.ql.util;  
  2.   
  3. import  java.util.*;  
  4.   
  5. import  android.content.Context;  
  6. import  android.util.Log;  
  7. import  android.view.*;  
  8. import  android.widget.BaseAdapter;  
  9. import  android.widget.Filter;  
  10. import  android.widget.Filterable;  
  11. import  android.widget.TextView;  
  12.   
  13. public   class  SearchAdapter<T>  extends  BaseAdapter  implements  Filterable {  
  14.     private  List<T> mObjects;  
  15.   
  16.     private  List<Set<String>> pinyinList; //支持多音字,类似:{{z,c},{j},{z},{q,x}}的集合   
  17.   
  18.     private   final  Object mLock =  new  Object();  
  19.   
  20.     private   int  mResource;  
  21.   
  22.     private   int  mFieldId =  0 ;  
  23.   
  24.     private  Context mContext;  
  25.   
  26.     private  ArrayList<T> mOriginalValues;  
  27.     private  ArrayFilter mFilter;  
  28.   
  29.     private  LayoutInflater mInflater;  
  30.   
  31.     public   static   final   int  ALL=- 1 ; //全部   
  32.     private   int  maxMatch= 10 ; //最多显示多少个可能选项   
  33.     //支持多音字   
  34.     public  SearchAdapter(Context context, int  textViewResourceId, T[] objects, int  maxMatch) {  
  35.         // TODO Auto-generated constructor stub   
  36.         init(context, textViewResourceId, 0 , Arrays.asList(objects));  
  37.         this .pinyinList = getHanziSpellList(objects);  
  38.         this .maxMatch=maxMatch;  
  39.     }  
  40.       
  41.     public  SearchAdapter(Context context, int  textViewResourceId, List<T> objects, int  maxMatch) {  
  42.         // TODO Auto-generated constructor stub   
  43.         init(context, textViewResourceId, 0 , objects);  
  44.         this .pinyinList = getHanziSpellList(objects);  
  45.         this .maxMatch=maxMatch;  
  46.     }  
  47.       
  48.     private   void  init(Context context,  int  resource,  int  textViewResourceId,List<T> objects) {  
  49.         mContext = context;  
  50.         mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  51.         mResource = resource;  
  52.         mObjects = objects;  
  53.         mFieldId = textViewResourceId;  
  54.     }  
  55.   
  56.       
  57.     /**  
  58.      * 获得汉字拼音首字母列表  
  59.      */   
  60.     private  List<Set<String>> getHanziSpellList(T[] hanzi){  
  61.         List<Set<String>> listSet=new  ArrayList<Set<String>>();  
  62.         PinYin4j pinyin=new  PinYin4j();  
  63.         for ( int  i= 0 ;i<hanzi.length;i++){  
  64.             listSet.add(pinyin.getPinyin(hanzi[i].toString()));  
  65.         }  
  66.         return  listSet;  
  67.     }  
  68.     /**  
  69.      * 获得汉字拼音首字母列表  
  70.      */   
  71.     private  List<Set<String>> getHanziSpellList(List<T> hanzi){  
  72.         List<Set<String>> listSet=new  ArrayList<Set<String>>();  
  73.         PinYin4j pinyin=new  PinYin4j();  
  74.         for ( int  i= 0 ;i<hanzi.size();i++){  
  75.             listSet.add(pinyin.getPinyin(hanzi.get(i).toString()));  
  76.         }  
  77.         return  listSet;  
  78.     }  
  79.       
  80.     public   int  getCount() {  
  81.         return  mObjects.size();  
  82.     }  
  83.   
  84.     public  T getItem( int  position) {  
  85.         return  mObjects.get(position);  
  86.     }  
  87.   
  88.     public   int  getPosition(T item) {  
  89.         return  mObjects.indexOf(item);  
  90.     }  
  91.   
  92.     public   long  getItemId( int  position) {  
  93.         return  position;  
  94.     }  
  95.   
  96.     public  View getView( int  position, View convertView, ViewGroup parent) {  
  97.         return  createViewFromResource(position, convertView, parent, mResource);  
  98.     }  
  99.   
  100.     private  View createViewFromResource( int  position, View convertView,  
  101.             ViewGroup parent, int  resource) {  
  102.         View view;  
  103.         TextView text;  
  104.   
  105.         if  (convertView ==  null ) {  
  106.             view = mInflater.inflate(resource, parent, false );  
  107.         } else  {  
  108.             view = convertView;  
  109.         }  
  110.   
  111.         try  {  
  112.             if  (mFieldId ==  0 ) {  
  113.                 text = (TextView) view;  
  114.             } else  {  
  115.                 text = (TextView) view.findViewById(mFieldId);  
  116.             }  
  117.         } catch  (ClassCastException e) {  
  118.             Log.e("ArrayAdapter" ,  
  119.                     "You must supply a resource ID for a TextView" );  
  120.             throw   new  IllegalStateException(  
  121.                     "ArrayAdapter requires the resource ID to be a TextView" , e);  
  122.         }  
  123.   
  124.         text.setText(getItem(position).toString());  
  125.   
  126.         return  view;  
  127.     }  
  128.   
  129.     public  Filter getFilter() {  
  130.         if  (mFilter ==  null ) {  
  131.             mFilter = new  ArrayFilter();  
  132.         }  
  133.         return  mFilter;  
  134.     }  
  135.   
  136.     private   class  ArrayFilter  extends  Filter {  
  137.         @Override   
  138.         protected  FilterResults performFiltering(CharSequence prefix) {  
  139.             FilterResults results = new  FilterResults();  
  140.   
  141.             if  (mOriginalValues ==  null ) {  
  142.                 synchronized  (mLock) {  
  143.                     mOriginalValues = new  ArrayList<T>(mObjects); //   
  144.                 }  
  145.             }  
  146.   
  147.             if  (prefix ==  null  || prefix.length() ==  0 ) {  
  148.                 synchronized  (mLock) {  
  149. //                  ArrayList<T> list = new ArrayList<T>();//无   
  150.                     ArrayList<T> list = new  ArrayList<T>(mOriginalValues); //List<T>   
  151.                     results.values = list;  
  152.                     results.count = list.size();  
  153.                 }  
  154.             } else  {  
  155.                 String prefixString = prefix.toString().toLowerCase();  
  156.   
  157.                 final  ArrayList<T> hanzi = mOriginalValues; //汉字String   
  158.                 final   int  count = hanzi.size();  
  159.   
  160.                 final  Set<T> newValues =  new  HashSet<T>(count); //支持多音字,不重复   
  161.   
  162.                 for  ( int  i =  0 ; i < count; i++) {  
  163.                     final  T value = hanzi.get(i); //汉字String   
  164.                     final  String valueText = value.toString().toLowerCase(); //汉字String   
  165.                     final  Set<String> pinyinSet=pinyinList.get(i); //支持多音字,类似:{z,c}   
  166.                     Iterator iterator= pinyinSet.iterator();//支持多音字   
  167.                     while  (iterator.hasNext()) { //支持多音字   
  168.                         final  String pinyin = iterator.next().toString().toLowerCase(); //取出多音字里的一个字母   
  169.                           
  170.                         if  (pinyin.indexOf(prefixString)!=- 1 ) { //任意匹配   
  171.                             newValues.add(value);  
  172.                         }   
  173.                         else   if  (valueText.indexOf(prefixString)!=- 1 ) { //如果是汉字则直接添加   
  174.                             newValues.add(value);  
  175.                         }  
  176.                     }  
  177.                     if (maxMatch> 0 ){ //有数量限制   
  178.                         if (newValues.size()>maxMatch- 1 ){ //不要太多   
  179.                             break ;  
  180.                         }  
  181.                     }  
  182.                       
  183.                 }  
  184.                 List<T> list=Set2List(newValues);//转成List   
  185.                 results.values = list;  
  186.                 results.count = list.size();  
  187.             }  
  188.             return  results;  
  189.         }  
  190.   
  191.         protected   void  publishResults(CharSequence constraint,FilterResults results) {  
  192.   
  193.             mObjects = (List<T>) results.values;  
  194.             if  (results.count >  0 ) {  
  195.                 notifyDataSetChanged();  
  196.             } else  {  
  197.                 notifyDataSetInvalidated();  
  198.             }  
  199.         }  
  200.     }  
  201.       
  202.     //List Set 相互转换   
  203.     public  <T  extends  Object> Set<T> List2Set(List<T> tList) {     
  204.         Set<T> tSet = new  HashSet<T>(tList);     
  205.         //TODO 具体实现看需求转换成不同的Set的子类。      
  206.         return  tSet;     
  207.     }  
  208.     public  <T  extends  Object> List<T> Set2List(Set<T> oSet) {     
  209.         List<T> tList = new  ArrayList<T>(oSet);     
  210.         // TODO 需要在用到的时候另外写构造,根据需要生成List的对应子类。      
  211.         return  tList;     
  212.     }  
  213. }  


在源码当中使用了PinYin4j去获得汉字的首字母,由于可能是多音字,所以将每个汉字的拼音都放在了Set中。当然PinYin4j很多强大的功能在这里都用不到,所以被我统统去掉了,这样大大提高了匹配效率。再看一下PinYin4j.java:

Java代码  收藏代码
  1. package  com.ql.util;  
  2.   
  3. import  java.util.Arrays;  
  4. import  java.util.HashSet;  
  5. import  java.util.Set;  
  6.   
  7. public   class  PinYin4j {  
  8.       
  9.       
  10.     public  PinYin4j(){  
  11.     }  
  12.     /**  
  13.      * 字符串集合转换字符串(逗号分隔)  
  14.      *   
  15.      * @author wyh  
  16.      * @param stringSet  
  17.      * @return  
  18.      */   
  19.     public  String makeStringByStringSet(Set<String> stringSet) {  
  20.         StringBuilder str = new  StringBuilder();  
  21.         int  i =  0 ;  
  22.         for  (String s : stringSet) {  
  23.             if  (i == stringSet.size() -  1 ) {  
  24.                 str.append(s);  
  25.             } else  {  
  26.                 str.append(s + "," );  
  27.             }  
  28.             i++;  
  29.         }  
  30.         return  str.toString().toLowerCase();  
  31.     }  
  32.   
  33.       
  34.     /**  
  35.      * 获取拼音集合  
  36.      *   
  37.      * @author wyh  
  38.      * @param src  
  39.      * @return Set<String>  
  40.      */   
  41.     public  Set<String> getPinyin(String src) {  
  42.             char [] srcChar;  
  43.             srcChar = src.toCharArray();  
  44.   
  45.             //1:多少个汉字   
  46.             //2:每个汉字多少种读音   
  47.             String[][] temp = new  String[src.length()][];  
  48.             for  ( int  i =  0 ; i < srcChar.length; i++) {  
  49.                 char  c = srcChar[i];  
  50.                 // 是中文或者a-z或者A-Z转换拼音(我的需求,是保留中文或者a-z或者A-Z)   
  51.                 if  (String.valueOf(c).matches( "[\\u4E00-\\u9FA5]+" )) {  
  52.                         String[] t = PinyinHelper.getUnformattedHanyuPinyinStringArray(c);  
  53.                         temp[i] = new  String[t.length];  
  54.                         for ( int  j= 0 ;j<t.length;j++){  
  55.                             temp[i][j]=t[j].substring(0 , 1 ); //获取首字母   
  56.                         }  
  57.                 } else   if  ((( int ) c >=  65  && ( int ) c <=  90 )  
  58.                         || ((int ) c >=  97  && ( int ) c <=  122 )||c>= 48 &&c<= 57 ||c== 42 ) { //a-zA-Z0-9*   
  59.                     temp[i] = new  String[] { String.valueOf(srcChar[i]) };  
  60.                 } else  {  
  61.                     temp[i] = new  String[] { "null!" };  
  62.                 }  
  63.                   
  64.             }  
  65.             String[] pingyinArray = paiLie(temp);  
  66.             return  array2Set(pingyinArray); //为了去掉重复项   
  67.     }  
  68.       
  69.     /*  
  70.      * 求2维数组所有排列组合情况  
  71.      * 比如:{{1,2},{3},{4},{5,6}}共有2中排列,为:1345,1346,2345,2346  
  72.      */   
  73.     private  String[] paiLie(String[][] str){  
  74.         int  max= 1 ;  
  75.         for ( int  i= 0 ;i<str.length;i++){  
  76.             max*=str[i].length;  
  77.         }  
  78.         String[] result=new  String[max];  
  79.         for ( int  i =  0 ; i < max; i++){  
  80.                 String s = "" ;  
  81.                 int  temp =  1 ;       //注意这个temp的用法。   
  82.                 for ( int  j =  0 ; j < str.length; j++){  
  83.                     temp *= str[j].length;  
  84.                     s += str[j][i / (max / temp) % str[j].length];  
  85.                 }  
  86.                 result[i]=s;  
  87.         }  
  88.           
  89.         return  result;  
  90.     }  
  91.       
  92.     public   static  <T  extends  Object> Set<T> array2Set(T[] tArray) {     
  93.         Set<T> tSet = new  HashSet<T>(Arrays.asList(tArray));     
  94.         // TODO 没有一步到位的方法,根据具体的作用,选择合适的Set的子类来转换。      
  95.         return  tSet;     
  96.     }   
  97.       
  98.     /**  
  99.      * @param args  
  100.      */   
  101.     public   static   void  main(String[] args) {  
  102.         //nongyeyinheng,nongyeyinhang,nongyeyinxing   
  103.         PinYin4j t=new  PinYin4j();  
  104.         String str = "农业银行1234567890abcdefghijklmnopqrstuvwxyz*" ;  
  105.         System.out.println(t.makeStringByStringSet(t.getPinyin(str)));  
  106.     }  
  107.   
  108. }  


这只是一个工具类,它使用到了PinyinHelper,PinyinHelper是加载字库文件用的,字库文件为/assets/unicode_to_hanyu_pinyin.txt,里面每一个汉字都对应着几个读音。

Java代码  收藏代码
  1. package  com.ql.util;  
  2.   
  3. import  java.io.BufferedInputStream;  
  4. import  java.io.FileNotFoundException;  
  5. import  java.io.IOException;  
  6. import  java.util.Properties;  
  7.   
  8. public   class  PinyinHelper{  
  9.     private   static  PinyinHelper instance;  
  10.     private  Properties properties =  null ;  
  11.       
  12.     public   static  String[] getUnformattedHanyuPinyinStringArray( char  ch){  
  13.         return  getInstance().getHanyuPinyinStringArray(ch);  
  14.     }  
  15.   
  16.     private  PinyinHelper(){  
  17.         initResource();  
  18.     }  
  19.   
  20.     public   static  PinyinHelper getInstance(){  
  21.         if (instance== null ){  
  22.             instance = new  PinyinHelper();  
  23.         }  
  24.         return  instance;  
  25.     }  
  26.       
  27.     private   void  initResource(){  
  28.         try {  
  29.             final  String resourceName =  "/assets/unicode_to_hanyu_pinyin.txt" ;  
  30. //          final String resourceName = "/assets/unicode_py.ini";   
  31.   
  32.             properties=new  Properties();  
  33.             properties.load(getResourceInputStream(resourceName));  
  34.   
  35.         } catch  (FileNotFoundException ex){  
  36.             ex.printStackTrace();  
  37.         } catch  (IOException ex){  
  38.             ex.printStackTrace();  
  39.         }  
  40.     }  
  41.   
  42.     private  BufferedInputStream getResourceInputStream(String resourceName){  
  43.         return   new  BufferedInputStream(PinyinHelper. class .getResourceAsStream(resourceName));  
  44.     }  
  45.       
  46.     private  String[] getHanyuPinyinStringArray( char  ch){  
  47.         String pinyinRecord = getHanyuPinyinRecordFromChar(ch);  
  48.   
  49.         if  ( null  != pinyinRecord){  
  50.             int  indexOfLeftBracket = pinyinRecord.indexOf(Field.LEFT_BRACKET);  
  51.             int  indexOfRightBracket = pinyinRecord.lastIndexOf(Field.RIGHT_BRACKET);  
  52.   
  53.             String stripedString = pinyinRecord.substring(indexOfLeftBracket  
  54.                     + Field.LEFT_BRACKET.length(), indexOfRightBracket);  
  55.   
  56.             return  stripedString.split(Field.COMMA);  
  57.   
  58.         } else   
  59.             return   null ;  
  60.           
  61.     }  
  62.       
  63.     private  String getHanyuPinyinRecordFromChar( char  ch){  
  64.         int  codePointOfChar = ch;  
  65.         String codepointHexStr = Integer.toHexString(codePointOfChar).toUpperCase();  
  66.         String foundRecord = properties.getProperty(codepointHexStr);  
  67.         return  foundRecord;  
  68.     }  
  69.   
  70.     class  Field{  
  71.         static   final  String LEFT_BRACKET =  "(" ;  
  72.         static   final  String RIGHT_BRACKET =  ")" ;  
  73.         static   final  String COMMA =  "," ;  
  74.     }  
  75.       
  76. }  


至于解析字库,比如有一个汉字是这样的格式:4E01 (ding1,zheng1),保存 到String[]当中就是{"ding1","zheng1"}这样的。但是这样的话到了PinYin4j中还需要使用substring(0,1)截 取首字母,效率有些低了,事实上文件中完全可以采用这样的格式存储:E01 (d,z),直接存汉字的首字母就行了,这个另论!

最后,看看使用方法:

Java代码  收藏代码
  1. public   class  QuickSearchActivity  extends  Activity {  
  2.     private   static   final  String tag= "QuickSearchActivity" ;  
  3.     private  AutoCompleteTextView search ;  
  4.     private  SlidingDrawer mDrawer;  
  5.       
  6.     public  SearchAdapter adapter= null ; //   
  7.     //需要读取   
  8.     public  String[] hanzi =  new  String[] {  
  9.             "长江证券100002" , "长江证券100001" "农业银行200001" , "工商银行300001"  ,   
  10.             "招商银行100001" "建设银行100001" "中国银行100002" "华夏银行500002" ,   
  11.             "上海银行100010" "浦发银行200009"   
  12.             };  
  13.       
  14.     /** Called when the activity is first created. */   
  15.     @Override   
  16.     public   void  onCreate(Bundle savedInstanceState) {  
  17.         super .onCreate(savedInstanceState);  
  18.         setContentView(R.layout.main);  
  19.           
  20.         initViews();  
  21.     }  
  22.       
  23.     private   void  initViews(){  
  24.         search = (AutoCompleteTextView) findViewById(R.id.search);  
  25.         search.setOnItemClickListener(new  OnItemClickListener() {  
  26.   
  27.             @Override   
  28.             public   void  onItemClick(AdapterView<?> arg0, View arg1,  int  position,  
  29.                     long  id) {  
  30.                 // TODO Auto-generated method stub   
  31.                 Log.d(tag, "onItemClick:" +position);  
  32.             }  
  33.               
  34.         });  
  35.           
  36.         search.setThreshold(1 );  
  37.           
  38.         adapter = new  SearchAdapter<String>( this ,  
  39.                 android.R.layout.simple_dropdown_item_1line, hanzi,SearchAdapter.ALL);//速度优先   
  40.         search.setAdapter(adapter);//   
  41.           
  42.         mDrawer = (SlidingDrawer) findViewById(R.id.slidingdrawer);  
  43.           
  44.     }  
  45.       
  46. }  




 

 

转自: http://gundumw100.iteye.com/blog/1331258

 

 

下载: dl.iteye.com/topics/download/bebae969-c880-37a0-9770-3a316438da81

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics