A-Z排序控件的實現


  • 前言

  最近項目需要做一個地區首字母a-z排序的效果,記錄一下自己如何實現的.

先看下效果圖:

  

  • 分析

這種效果自己實現還是第一次;之前見過這種效果:

這些字母都是onDraw畫上去的;只要知道每個字母的left,top,right,bottom就能知道它的具體位置,所以onMeasure方法中要確定每個單元格的寬高.文字排序可以先把漢字轉換成拼音,再去比較首字母的順序(特殊地區特殊處理,比如重慶);

具體看下是如何確定字母的位置:

於是乎,代碼就出來了:

  1 public class QuickIndexBar extends View {
  2     
  3     private OnLetterUpdateListener onLetterUpdateListener;
  4     
  5     public interface OnLetterUpdateListener{
  6         void onLetterUpdate(String letter);
  7     }
  8     
  9     public OnLetterUpdateListener getOnLetterUpdateListener() {
 10         return onLetterUpdateListener;
 11     }
 12 
 13     public void setOnLetterUpdateListener(
 14             OnLetterUpdateListener onLetterUpdateListener) {
 15         this.onLetterUpdateListener = onLetterUpdateListener;
 16     }
 17     private static final String[] LETTERS = new String[]{
 18         "A", "B", "C", "D", "E", "F",
 19         "G", "H", "I", "J", "K", "L",
 20         "M", "N", "O", "P", "Q", "R",
 21         "S", "T", "U", "V", "W", "X",
 22         "Y", "Z"
 23     };
 24     
 25     private Paint paint;
 26 
 27     // 單元格寬度
 28     private int cellWidth;
 29 
 30     // 單元格高度
 31     private float cellHeight;
 32 
 33 
 34     public QuickIndexBar(Context context) {
 35         this(context, null);
 36     }
 37 
 38     public QuickIndexBar(Context context, AttributeSet attrs) {
 39         this(context, attrs, 0);
 40     }
 41 
 42     public QuickIndexBar(Context context, AttributeSet attrs, int defStyle) {
 43         super(context, attrs, defStyle);
 44         // 創建一個抗鋸齒的畫筆
 45         paint = new Paint(Paint.ANTI_ALIAS_FLAG);
 46         // 畫筆文本加粗
 47         paint.setTypeface(Typeface.DEFAULT_BOLD);
 48         // 顏色
 49         paint.setColor(Color.WHITE);
 50     }
 51     
 52     @Override
 53     protected void onDraw(Canvas canvas) {
 54         
 55         // 遍歷26個英文字母, 計算坐標, 進行繪制
 56         for (int i = 0; i < LETTERS.length; i++) {
 57             String letter = LETTERS[i];
 58             
 59             // 計算x坐標
 60             float x = cellWidth * 0.5f - paint.measureText(letter) * 0.5f;
 61             // 計算y坐標
 62             Rect bounds = new Rect();
 63             // 獲取文本的矩形區域
 64             paint.getTextBounds(letter, 0, letter.length(), bounds);
 65             
 66             float y = cellHeight * 0.5f + bounds.height() * 0.5f + i * cellHeight;
 67             
 68             // 繪制文本
 69             canvas.drawText(letter, x, y, paint);
 70         }
 71     }
 72     private int lastIndex = -1;
 73     
 74     @Override
 75     public boolean onTouchEvent(MotionEvent event) {
 76         
 77         float y;
 78         int currentIndex;
 79         
 80         switch (event.getAction()) {
 81         case MotionEvent.ACTION_DOWN:
 82             // 獲取被點擊到的字母索引
 83             y = event.getY();
 84             // 根據y值, 計算當前按下的字母位置
 85             currentIndex = (int) (y / cellHeight);
 86             if(currentIndex != lastIndex){
 87                 if(currentIndex >= 0 && currentIndex < LETTERS.length){
 88                     String letter = LETTERS[currentIndex];
 89                     if(onLetterUpdateListener != null){
 90                         onLetterUpdateListener.onLetterUpdate(letter);
 91                     }
 92                     System.out.println("letter: " + letter);
 93                     // 記錄上一次觸摸的字母
 94                     lastIndex = currentIndex;
 95                 }
 96             }
 97             
 98             break;
 99         case MotionEvent.ACTION_MOVE:
100             // 獲取被點擊到的字母索引
101             y = event.getY();
102             // 根據y值, 計算當前按下的字母位置
103             currentIndex = (int) (y / cellHeight);
104             if(currentIndex != lastIndex){
105                 if(currentIndex >= 0 && currentIndex < LETTERS.length){
106                     String letter = LETTERS[currentIndex];
107                     if(onLetterUpdateListener != null){
108                         onLetterUpdateListener.onLetterUpdate(letter);
109                     }
110                     System.out.println("letter: " + letter);
111                     // 記錄上一次觸摸的字母
112                     lastIndex = currentIndex;
113                 }
114             }
115             
116             break;
117         case MotionEvent.ACTION_UP:
118             lastIndex = -1;
119             break;
120         default:
121             break;
122         }
123         
124         return true;
125     }
126     
127     @Override
128     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
129         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
130         int mHeight = getMeasuredHeight();
131         cellWidth = getMeasuredWidth();
132         cellHeight = mHeight * 1.0f / LETTERS.length;
133     }
134     
135     
136 
137 }

這種豎直的簡單快速索引就搞定了,此外還添加了觸摸和點擊的監聽

  • 實現

再來看下我們要的效果圖那種效果是如何實現的;主要區別就是字母所在位置和觸摸位置的差異,偷點懶,直接上代碼了:

 1   @Override
 2     protected void onDraw(Canvas canvas) {
 3 
 4         // 遍歷26個英文字母, 計算坐標, 進行繪制
 5         for (int i = 0; i < LETTERS.length; i++) {
 6             String letter = LETTERS[i];
 7 
 8             // 計算x坐標
 9 //            float x = cellWidth * 0.5f - paint.measureText(letter) * 0.5f;
10             float y = cellHeight * 0.5f + paint.measureText(letter) * 0.5f;
11             // 計算y坐標
12             Rect bounds = new Rect();
13             // 獲取文本的矩形區域
14             paint.getTextBounds(letter, 0, letter.length(), bounds);
15 
16 //            float y = cellHeight * 0.5f + bounds.height() * 0.5f + i * cellHeight;
17             float x = cellWidth * 0.5f + bounds.width() * 0.5f + i * cellWidth;
18             // 繪制文本
19             canvas.drawText(letter, x, y, paint);
20         }
21     }
22 
23     private int lastIndex = -1;
24 
25     @Override
26     public boolean onTouchEvent(MotionEvent event) {
27 
28         float x;
29         int currentIndex;
30 
31         switch (event.getAction()) {
32             case MotionEvent.ACTION_DOWN:
33                 // 獲取被點擊到的字母索引
34                 x = event.getX();
35                 // 根據x值, 計算當前按下的字母位置
36                 currentIndex = (int) (x / cellWidth);
37                 if (currentIndex != lastIndex) {
38                     if (currentIndex >= 0 && currentIndex < LETTERS.length) {
39                         String letter = LETTERS[currentIndex];
40                         if (onLetterUpdateListener != null) {
41                             onLetterUpdateListener.onLetterUpdate(letter);
42                         }
43                         // 記錄上一次觸摸的字母
44                         lastIndex = currentIndex;
45                     }
46                 }
47 
48                 break;
49             case MotionEvent.ACTION_MOVE:
50                 // 獲取被點擊到的字母索引
51                 x = event.getX();
52                 // 根據y值, 計算當前按下的字母位置
53                 currentIndex = (int) (x / cellWidth);
54                 if (currentIndex != lastIndex) {
55                     if (currentIndex >= 0 && currentIndex < LETTERS.length) {
56                         String letter = LETTERS[currentIndex];
57                         if (onLetterUpdateListener != null) {
58                             onLetterUpdateListener.onLetterUpdate(letter);
59                         }
60                         // 記錄上一次觸摸的字母
61                         lastIndex = currentIndex;
62                     }
63                 }
64 
65                 break;
66             case MotionEvent.ACTION_UP:
67                 lastIndex = -1;
68                 break;
69             default:
70                 break;
71         }
72 
73         return true;
74     }
75 
76     @Override
77     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
78         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
79         int mWidth = getMeasuredWidth();
80         cellWidth = mWidth * 1.0f / LETTERS.length;
81         cellHeight = getMeasuredHeight();
82     }

可以看到主要區別就是單元格的寬度和高度相應改變了;后面會補充一張計算草圖.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM