帶索引欄的listview,在android開發非常普遍,方便用戶進行字母索引,就像微信通訊錄這樣:
今天,我們就從零到一實現這個具有索引欄的listview.
怎么實現這個控件了,我們應當梳理出一個思路。
①首先應當將字母的索引欄繼承與一個控件,通過ondraw方法將字母畫出來。
②然后我們應該監聽這個字母控件的ontouch事件,來判斷用戶到底是按了那個字母。
③就是實現這個索引欄與listview的聯動,就是將listview滑動到按下字母的位置。
大體流程圖如下:
有了前面鋪墊,我們引出本文重頭戲——代碼。
首先,索引欄這個控件如何將字母繪制在控件上的代碼:
/** * 側邊欄顯示字母 */ private String[] words = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#" }; /** * 繪制列表控件的方法 * 將要繪制的字母以從上到下的順序繪制在一個指定區域 * 如果是進行選中的字母就進行高亮顯示 */ @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); int height = getHeight();// 獲取對應高度 int width = getWidth(); // 獲取對應寬度 int singleHeight = height / words.length;// 獲取每一個字母的高度 for (int i = 0; i < words.length; i++) { paint.setColor(Color.rgb(33, 65, 98)); // paint.setColor(Color.WHITE); paint.setTypeface(Typeface.DEFAULT_BOLD); paint.setAntiAlias(true); paint.setTextSize(20f); // 選中的狀態 if (isdown) { paint.setColor(Color.parseColor("#ffffff")); //paint.setFakeBoldText(true); } // x坐標等於中間-字符串寬度的一半. float xPos = width / 2 - paint.measureText(words[i]) / 2; float yPos = singleHeight * i + singleHeight; canvas.drawText(words[i], xPos, yPos, paint); paint.reset();// 重置畫筆 } }
通過上述的代碼,我們可以得出以下的結論:將要繪制的字母以從上到下的順序繪制在一個指定區域,每個字母的x坐標是一樣的,x坐標即為控件寬度一半。如果當前字母選中的話,就高亮顯示。思路如圖所示:
緊接着,就來到第二步,確定用戶到底點擊是那個字母,代碼如下:
/** * 處理觸摸事件的方法 * 用戶按下時候,整個控件背景變化 * 根據按下y坐標 判斷究竟用戶按下那個字母 * 當前字母高亮顯示 將其字母顯示listview中央 */ @Override public boolean dispatchTouchEvent(MotionEvent event) { int action = event.getAction(); final float y = event.getY();// 點擊y坐標 final int oldChoose = choose; final ITouchingLetterChangedListener listener = onTouchingLetterChangedListener; final int c = (int) (y / getHeight() * words.length);// 點擊y坐標所占總高度的比例*b數組的長度就等於點擊b中的個數. switch (action) { case MotionEvent.ACTION_UP: isdown=false; setBackgroundResource(android.R.color.transparent); choose = -1;// invalidate(); if (textViewDialog != null) { textViewDialog.setVisibility(View.INVISIBLE); } break; default: isdown=true; setBackgroundResource(R.color.sidebar_bg_color); if (oldChoose != c) { if (c >= 0 && c < words.length) { if (listener != null) { listener.OnTouchingLetterChanged(words[c]); } if (textViewDialog != null) { textViewDialog.setText(words[c]); textViewDialog.setVisibility(View.VISIBLE); } choose = c; invalidate(); } } break; } return true; }
通過上述的代碼,我們可以這樣總結:當用戶按下的時候,整個控件背景發生變化,根據用戶按下的y坐標來確定用戶究竟是按下那個字母,並且將按下字母顯示屏幕的中央,效果圖如下:
最終,將listview 移動到按下字母相應位置,代碼如下:
/** * 根據用戶點擊那個字母將listview移動到相應位置 */ sidebar.setOnTouchingLetterChangedListener(new ITouchingLetterChangedListener() { @Override public void OnTouchingLetterChanged(String cString) { int position = -1; if (cString.length() > 0) { position = myAdapter.getPositionForSection(cString .charAt(0)); } if (position != -1) { listview.setSelection(position); } else if (cString.contains("#")) { listview.setSelection(0); } } });
連篇累牘說了這么多,控件大功告成的效果為:
源代碼地址為:
http://pan.baidu.com/s/1dDMDjhR