android之带右侧字母(拼音)索引的列表

 在开发app的过程中,如果用到通讯录或者类似的列表,需要快速在其中定位,可以根据列表项的拼音首字母来定位,这时候就需要用到右侧字母索引了。必如现在的微信通讯录界面就是如此。在实现这种功能的过程中,还是挺复杂的,很难我觉得。在网上各种查找资料,困难重重,好在最后终于捯饬出来了,伤不起。。。。特此记录一下写的过程。

 

1、创建自定的view,用作右侧列表索引。

 

Java代码   收藏代码
  1. public class RulerWidget extends View {  
  2.       
  3.     public static String[] indexStr = {  
  4.         "#""A""B""C""D""E""F""G""H",  
  5.         "I""J""K""L""M""N""O""P""Q",  
  6.         "R""S""T""U""V""W""X""Y""Z"  
  7.         };  
  8.     public static int INDEX_LENGTH = indexStr.length;  
  9.       
  10.     OnTouchingLetterChangedListener onTouchingLetterChangedListener;   
  11.     Paint mPaint = new Paint();  
  12.     boolean showBkg = false;  
  13.     int choose = -1;  
  14.       
  15.     public RulerWidget(Context context) {  
  16.         super(context);  
  17.     }  
  18.       
  19.     public RulerWidget(Context context, AttributeSet attrs, int defStyle) {  
  20.         super(context, attrs, defStyle);  
  21.     }  
  22.       
  23.     public RulerWidget(Context context, AttributeSet attrs) {  
  24.         super(context, attrs);  
  25.     }  
  26.       
  27.     @Override  
  28.     protected void onDraw(Canvas canvas) {  
  29.         super.onDraw(canvas);  
  30. //      if(showBkg){    
  31.             canvas.drawColor(Color.parseColor("#40000000"));    
  32. //       }    
  33.                         
  34.         int height = getHeight();    
  35.         int width = getWidth();    
  36.         int singleHeight = height / indexStr.length;    
  37.         for(int i=0;i<indexStr.length;i++){    
  38.             mPaint.setColor(Color.WHITE);  
  39.             mPaint.setTextSize(24);  
  40.             mPaint.setTypeface(Typeface.DEFAULT_BOLD);    
  41.             mPaint.setAntiAlias(true);    
  42.             if(i == choose){    
  43.                 mPaint.setColor(Color.parseColor("#3399ff"));    
  44.                 mPaint.setFakeBoldText(true);    
  45.              }    
  46.             float xPos = width/2  - mPaint.measureText(indexStr[i])/2;    
  47.             float yPos = singleHeight * i + singleHeight;    
  48.             canvas.drawText(indexStr[i], xPos, yPos, mPaint);    
  49.             mPaint.reset();    
  50.         }    
  51.   
  52.     }  
  53.       
  54.       @Override    
  55.         public boolean dispatchTouchEvent(MotionEvent event) {    
  56.             final int action = event.getAction();    
  57.             final float y = event.getY();    
  58.             final int oldChoose = choose;    
  59.             final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;    
  60.             final int c = (int) (y/getHeight()*indexStr.length);    
  61.                 
  62.             switch (action) {    
  63.                 case MotionEvent.ACTION_DOWN:    
  64.                     showBkg = true;    
  65.                     if(oldChoose != c && listener != null){    
  66.                         if(c > 0 && c< indexStr.length){    
  67.                             listener.onTouchingLetterChanged(indexStr[c]);    
  68.                             choose = c;    
  69.                             invalidate();    
  70.                         }    
  71.                     }    
  72.                         
  73.                     break;    
  74.                 case MotionEvent.ACTION_MOVE:    
  75.                     if(oldChoose != c && listener != null){    
  76.                         if(c > 0 && c< indexStr.length){    
  77.                             listener.onTouchingLetterChanged(indexStr[c]);    
  78.                             choose = c;    
  79.                             invalidate();    
  80.                         }    
  81.                     }    
  82.                     break;    
  83.                 case MotionEvent.ACTION_UP:    
  84. //                  showBkg = false;    
  85.                     choose = -1;    
  86.                     invalidate();    
  87.                     break;    
  88.             }    
  89.             return true;    
  90.         }    
  91.         
  92.         @Override    
  93.         public boolean onTouchEvent(MotionEvent event) {    
  94.             return super.onTouchEvent(event);    
  95.         }    
  96.         
  97.         public void setOnTouchingLetterChangedListener(    
  98.                 OnTouchingLetterChangedListener onTouchingLetterChangedListener) {    
  99.             this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;    
  100.         }    
  101.         
  102. }  

 

对应的回调接口定义:

Java代码   收藏代码
  1. /**   
  2.  * @date 2014-9-3 
  3.  * @Description: ruler触摸回调 
  4.  */  
  5. public interface OnTouchingLetterChangedListener{    
  6.     public void onTouchingLetterChanged(String s);    
  7. }    

 

 

2、创建fragment片段对应的布局文件:

 

Xml代码   收藏代码
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:orientation="vertical" >  
  6.   
  7.     <FrameLayout  
  8.         android:layout_width="match_parent"  
  9.         android:layout_height="match_parent"  
  10.         android:background="#ffffff" >  
  11.   
  12.         <ListView  
  13.             android:id="@+id/listView"  
  14.             android:layout_width="match_parent"  
  15.             android:layout_height="wrap_content"  
  16.             android:cacheColorHint="#00000000"  
  17.             android:fadingEdge="none"  
  18.             android:scrollbars="none" >  
  19.   
  20.         </ListView>  
  21.           
  22.         <TextView  
  23.             android:id="@+id/tv"  
  24.             android:layout_width="60dp"  
  25.             android:layout_height="60dp"  
  26.             android:gravity="center"  
  27.             android:background="#f0606060"  
  28.             android:layout_gravity="center"  
  29.             android:text="A"  
  30.             android:textColor="#ffffff"  
  31.             android:textSize="30sp" />  
  32.   
  33.          <com.hy.ticket.view.RulerWidget  
  34.             android:id="@+id/sidrbar"  
  35.             android:layout_width="30.0dip"  
  36.             android:layout_height="fill_parent"  
  37.             android:layout_gravity="right|center"  />    
  38.     </FrameLayout>  
  39.   
  40. </LinearLayout>  

 

 

3、引入pinyin4j.jar包(版本建议使用最新),写一个工具类,包含获取中文字符串拼音首字母,获取中文拼音等方法。

 

Java代码   收藏代码
  1. public class StringHelper {  
  2.       
  3.     public static String getPingYin(String src) {  
  4.         char[] t = src.toCharArray();  
  5.         String[] strs = new String[t.length];  
  6.         HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();  
  7.         format.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
  8.         format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
  9.         format.setVCharType(HanyuPinyinVCharType.WITH_V);  
  10.         String str = "";  
  11.         try{  
  12.             for(int i=0; i<t.length; i++) {  
  13.                 if(java.lang.Character.toString(t[i]).matches(  
  14.                         "[\\u4E00-\\u9FA5]+")) {  
  15.                     strs = PinyinHelper.toHanyuPinyinStringArray(t[i], format);  
  16.                     str += strs[0];  
  17.                 }else{  
  18.                     str += java.lang.Character.toString(t[i]);  
  19.                 }  
  20.             }  
  21.             //长沙,长春多音字处理  
  22.             if(str.equals("zhangsha")) {  
  23.                 str = "changsha";  
  24.             }  
  25.             if(str.equals("zhangchun")) {  
  26.                 str = "changchun";  
  27.             }  
  28.             return str;  
  29.         }catch(Exception e) {  
  30.             e.printStackTrace();  
  31.         }  
  32.         return str;  
  33.     }  
  34.       
  35.     public static String getHeaderChar(String src) {  
  36.         String convert = "";  
  37.         char word = src.charAt(0);  
  38.         String[] arr = PinyinHelper.toHanyuPinyinStringArray(word);  
  39.         if(arr != null) {  
  40.             convert += arr[0].charAt(0);  
  41.         }else{  
  42.             convert += word;  
  43.         }  
  44.         return convert.toUpperCase();  
  45.     }  
  46.       
  47.     public static String getPinYinHeaderChar(String src) {  
  48.         String convert = "";  
  49.         for(int i=0; i<src.length(); i++) {  
  50.             char word = src.charAt(i);  
  51.             String[] arr = PinyinHelper.toHanyuPinyinStringArray(word);  
  52.             if(arr != null) {  
  53.                 convert += arr[0].charAt(0);  
  54.             }else{  
  55.                 convert += word;  
  56.             }  
  57.         }  
  58.         return convert.toUpperCase();  
  59.     }  
  60.       
  61. }  

 

 

4、建立一个工具类,用于根据首字母排序,获取大些字母及对应的中文字符串(如A 阿尔法 B 北京 C 长沙 长春 常州等):

 

Java代码   收藏代码
  1. public class SortUtil {  
  2.       
  3.     public static List<Station> sortList(String[] srcNames, List<Station> list) {  
  4.         List<Station> newList = new ArrayList<Station>();  
  5.         for(int i=0; i<srcNames.length; i++) {  
  6.             if(srcNames[i].length() != 1) {  
  7.                 for(int j=0; j<list.size(); j++) {  
  8.                     if(srcNames[i].equals(list.get(j).getPinYinName())) {  
  9.                         Station s = new Station(list.get(j).getName(), list.get(j).getPinYinName());  
  10.                         newList.add(s);  
  11.                     }  
  12.                 }  
  13.             }else{  
  14.                 newList.add(new Station(srcNames[i]));  
  15.             }  
  16.         }  
  17.         return newList;  
  18.     }  
  19.       
  20.     public static String[] sortIndex(List<Station> stations) {    
  21.                 TreeSet<String> set = new TreeSet<String>();    
  22.                 // 获取初始化数据源中的首字母,添加到set中    
  23.                 for (Station station : stations) {    
  24.                     set.add(StringHelper.getPinYinHeaderChar(station.getName()).substring(    
  25.                             01));    
  26.                 }    
  27.                 // 新数组的长度为原数据加上set的大小    
  28.                 String[] names = new String[stations.size() + set.size()];    
  29.                 int i = 0;    
  30.                 for (String string : set) {    
  31.                     names[i] = string;    
  32.                     i++;    
  33.                 }    
  34.                 String[] pinYinNames = new String[stations.size()];    
  35.                 for (int j = 0; j < stations.size(); j++) {    
  36.                     stations.get(j).setPinYinName(    
  37.                             StringHelper    
  38.                                     .getPingYin(stations.get(j).getName().toString()));    
  39.                     pinYinNames[j] = StringHelper.getPingYin(stations.get(j).getName()    
  40.                             .toString());    
  41.                 }    
  42.                 // 将原数据拷贝到新数据中    
  43.                 System.arraycopy(pinYinNames, 0, names, set.size(), pinYinNames.length);    
  44.                 // 自动按照首字母排序    
  45.                 Arrays.sort(names, String.CASE_INSENSITIVE_ORDER);    
  46.                 return names;    
  47.             }    
  48.   
  49. }  

 

listViewAdapter,填充ListView的适配器:

Java代码   收藏代码
  1. public class ListViewAdapter extends BaseAdapter {  
  2.       
  3.     private Context context;  
  4.     private List<Station> stations;  
  5.     private ViewHolder viewHolder;  
  6.       
  7.     public ListViewAdapter(Context context, List<Station> stations) {  
  8.         this.context = context;  
  9.         this.stations = stations;  
  10.     }  
  11.   
  12.     @Override  
  13.     public int getCount() {  
  14.         return stations.size();  
  15.     }  
  16.   
  17.     @Override  
  18.     public Object getItem(int position) {  
  19.         return stations.get(position);  
  20.     }  
  21.   
  22.     @Override  
  23.     public long getItemId(int position) {  
  24.         return position;  
  25.     }  
  26.       
  27.     @Override    
  28.     public boolean isEnabled(int position) {    
  29.         if (stations.get(position).getName().length() == 1)// 如果是字母索引    
  30.            return false;// 表示不能点击    
  31.         return super.isEnabled(position);    
  32.     }    
  33.       
  34.     @Override  
  35.     public View getView(int position, View convertView, ViewGroup parent) {  
  36.         String item = stations.get(position).getName();  
  37.         viewHolder = new ViewHolder();  
  38.         if(item.length() == 1) {  
  39.             convertView = LayoutInflater.from(context).inflate(R.layout.index, null);  
  40.             TextView indexTV = (TextView) convertView.findViewById(R.id.indexTV);  
  41.             indexTV.setText(stations.get(position).getName());  
  42.             viewHolder.indexTV = indexTV;  
  43.         }else{  
  44.             convertView = LayoutInflater.from(context).inflate(R.layout.item, null);  
  45.             TextView itemTV = (TextView) convertView.findViewById(R.id.itemTV);  
  46.             itemTV.setText(stations.get(position).getName());  
  47.             viewHolder.itemTV = itemTV;  
  48.         }  
  49.         return convertView;  
  50.     }  
  51.       
  52.     //内部类  
  53.     private class ViewHolder {  
  54.         private TextView itemTV;  
  55.         private TextView indexTV;  
  56.     }  
  57. }  

 

 

 

5、最后一步,建立布局文件对应的fragment片段(或Activity,这里使用的是fragment):

 

Java代码   收藏代码
  1. public class ListStation extends Fragment {  
  2.       
  3.     private Map<String, Integer> selector;  
  4.     private LinearLayout layoutIndex;  
  5.     private ListView listView;  
  6.     private TextView textView;  
  7.     private ListViewAdapter adapter;  
  8.     private String[] sections = {  
  9.             "#""A""B""C""D""E""F""G""H",  
  10.             "I""J""K""L""M""N""O""P""Q",  
  11.             "R""S""T""U""V""W""X""Y""Z"  
  12.             };  
  13.     private List<Station> stations;  
  14.     private List<Station> newStations;  
  15.     private int height;  
  16.     private boolean flag = false;  
  17.     private LinearLayout layout;  
  18.     private RulerWidget ruler;  
  19.       
  20.     private Handler handler;  
  21.     private OverlayThread overlayThread;  
  22.       
  23.     @Override  
  24.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  25.             Bundle savedInstanceState) {  
  26.         View view = inflater.inflate(R.layout.station_list, container, false);  
  27.         listView = (ListView) view.findViewById(R.id.listView);  
  28.         textView = (TextView) view.findViewById(R.id.tv);  
  29.         ruler = (RulerWidget) view.findViewById(R.id.sidrbar);  
  30.         ruler.setOnTouchingLetterChangedListener(new LetterListViewListener());  
  31.           
  32.           
  33.         initOverlay();  
  34.         return view;  
  35.     }  
  36.       
  37.     @Override  
  38.     public void onActivityCreated(Bundle savedInstanceState) {  
  39.         super.onCreate(savedInstanceState);  
  40.           
  41.         stations = StationService.getAllStation();  
  42.         String[] allNames = SortUtil.sortIndex(stations);  
  43.         newStations = SortUtil.sortList(allNames, stations);  
  44.           
  45.         //这个map是建立大写字母对应位于listView位置的索引  
  46.         selector = new HashMap<String, Integer>();  
  47.         for(int i=0; i<allNames.length; i++) {  
  48.             if(allNames[i].length() == 1) {  
  49.                 selector.put(allNames[i], i);  
  50.             }  
  51.         }  
  52.         adapter = new ListViewAdapter(getActivity(), newStations);  
  53.         listView.setAdapter(adapter);  
  54.           
  55.         handler = new Handler();  
  56.         overlayThread = new OverlayThread();  
  57.     }  
  58.       
  59.     //初始化汉语拼音首字母弹出提示框  
  60.     private void initOverlay() {  
  61.         LayoutInflater inflater = LayoutInflater.from(getActivity());  
  62. //      overlay = (TextView) inflater.inflate(R.layout.overlay, null);  
  63.         textView.setVisibility(View.INVISIBLE);  
  64.         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(  
  65.                 LayoutParams.WRAP_CONTENT,   
  66.                 LayoutParams.WRAP_CONTENT,  
  67.                 WindowManager.LayoutParams.TYPE_APPLICATION,  
  68.                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,  
  69.                 PixelFormat.TRANSLUCENT);  
  70.         WindowManager windowManager = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);  
  71. //      windowManager.addView(textView, lp);  
  72.     }  
  73.       
  74.     private class LetterListViewListener implements OnTouchingLetterChangedListener{  
  75.   
  76.         @Override  
  77.         public void onTouchingLetterChanged(final String s) {  
  78.             if(selector.get(s) != null) {  
  79.                 int position = selector.get(s);  
  80.                 listView.setSelection(position);  
  81.                   
  82.                 textView.setText(s);  
  83.                 textView.setVisibility(View.VISIBLE);  
  84.                 handler.removeCallbacks(overlayThread);  
  85.                 //延迟一秒后执行,让overlay为不可见  
  86.                 handler.postDelayed(overlayThread, 1500);  
  87.             }   
  88.         }  
  89.           
  90.     }  
  91.       
  92.     //设置overlay不可见  
  93.     private class OverlayThread implements Runnable {  
  94.   
  95.         @Override  
  96.         public void run() {  
  97.             textView.setVisibility(View.GONE);  
  98.         }  
  99.           
  100.     }  
  101.     /*class GetDataAsyTask extends AsyncTask { 
  102.          
  103.         @Override 
  104.         protected void onPreExecute() { 
  105.             super.onPreExecute(); 
  106.         } 
  107.          
  108.         @Override 
  109.         protected Object doInBackground(Object... params) { 
  110.             stations = StationService.getAllStation(); 
  111.             String[] allNames = SortUtil.sortIndex(stations); 
  112.             newStations = SortUtil.sortList(allNames, stations); 
  113.             if(newStations != null) { 
  114.                 newStations.clear(); 
  115.                 newStations = null; 
  116.             } 
  117.             if(stations != null) { 
  118.                 stations.clear(); 
  119.                 stations = null; 
  120.             } 
  121.             if(allNames != null) { 
  122.                 allNames = null; 
  123.             } 
  124.             return null; 
  125.         } 
  126.          
  127.         @Override 
  128.         protected void onPostExecute(Object result) { 
  129. //          super.onPostExecute(result); 
  130.             if(newStations == null) { 
  131. //              textView.setVisibility(View.VISIBLE); 
  132.                 return; 
  133.             } 
  134.             handleSuccessData(); 
  135.         } 
  136.          
  137.     } 
  138.      
  139.     private Integer getPosition(final int j) { 
  140.            Integer pos = null; 
  141.            int i = j; 
  142.            while (pos == null && i <= RulerWidget.indexStr.length - 1) { 
  143.                pos = selector.get(RulerWidget.indexStr[i]); 
  144.                i++; 
  145.            } 
  146.            if (pos == null) { 
  147.                pos = newStations.size() - 1; 
  148.            } 
  149.            return pos; 
  150.         } 
  151.  
  152.      
  153.     private void handleSuccessData() { 
  154.            listView.setVisibility(View.VISIBLE); 
  155.            ruler.setVisibility(View.VISIBLE); 
  156.            adapter = new ListViewAdapter(getActivity(), newStations); 
  157.            ruler.setOnRulerTouch(new OnRulerTouch() { 
  158.              
  159.             @Override 
  160.             public void onUP() { 
  161.             } 
  162.              
  163.             @Override 
  164.             public void onOthers() { 
  165.             } 
  166.              
  167.             @Override 
  168.             public void onMove(int position) { 
  169.                 textView.setText(RulerWidget.indexStr[position]); 
  170.                 listView.setSelection(getPosition(position)); 
  171.             } 
  172.              
  173.             @Override 
  174.             public void onDown(int position) { 
  175.                 textView.setVisibility(View.VISIBLE); 
  176.                 textView.setText(RulerWidget.indexStr[position]); 
  177.                 listView.setSelection(getPosition(position)); 
  178.             } 
  179.         }); 
  180.             
  181.            listView.setAdapter(adapter); 
  182.            adapter.notifyDataSetChanged(); 
  183.             
  184.         } 
  185. */  
  186. }  

 

 

这样,带拼音索引的listView建立完成。。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值