今天練習了一下手機聯系人快速索引的自定義View,依例看下效果圖:
先來張極具爆發力的大月亮珠聯璧合組合:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiQ3chVEa0V3bT9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwVPFdUYoh2VhFjSzoVdsdkW0Z0VhZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39TMwQDO1gjM2EzMxMDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
效果圖:
觀今夜星,額不,觀效果很多同學一下子可能感覺很複雜,沒錯,确實蠻複雜的。不過分析一下就很簡單了,整個布局分為三塊:
- 鋪滿螢幕的清單控件(這裡用的是Recycleview)
- 中間顯示字幕的正方形
- 右側可滑動、點選的不知啥玩意
完成布局除了右側的東西其他都很簡單,那麼重點就是在右側的滑動控件了,沒錯,這玩意就是這個效果的最主要成員,暫且命名其為IndexWord(字幕索引),下面我們一步步來實作效果:
1.IndexWord自定義的初始化以及字幕的呈現
public class IndexWord extends View {
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"};
private TextPaint textPaint;//文本畫筆
private int everywidth;//每一個字母單元格的寬度
private int length;//words長度,
private int everyheght;//每一個字母單元格的高度
private Rect rect;//矩形
private int index = -;//用于touchevent中記錄點選的是哪個字幕
public IndexWord(Context context) {
this(context, null);
}
public IndexWord(Context context, AttributeSet attrs) {
this(context, attrs, );
}
public IndexWord(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initpaint();
}
當然這裡的words可以通過各種途徑獲得到,看屬性就知道不怎麼複雜,主要是怎麼把字幕(漢子也可以)平均的畫出來,那麼問題轉化為如何獲得每個字母的坐标x,y了。自古文字留不住,唯有圖檔得人心,看一下下圖應該就了解了:
drawtext中 x,y的坐标是可以更改的,需要注意的是預設情況下y的坐标是底線上的坐标值,
下面是onDraw中的代碼:
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
initheight();
for (int i = ; i < length; i++) {
String word = words[i];
textPaint.getTextBounds(word, , , rect);
int width = rect.width();
int height = rect.height();
if (index == i) {
textPaint.setColor(Color.RED);
} else {
textPaint.setColor(Color.BLACK);
}
canvas.drawText(word, everywidth / - width / , everyheght * i+(everyheght/+ height/), textPaint);
}
}
這樣就把各個字幕畫在 了控件上,裡面的之是以有if判斷,待會會講到。
2.點選滑動事件的添加
仔細看的同學應該注意到了,當點選或者滑動到某個字母的時候,改字幕是要變色的,自然而然的就要處理觸屏事件了,重寫onTouchEvent方法如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN|MotionEvent.ACTION_MOVE:
index = (int) (event.getY() / everyheght);
if (indexPressWord != null && index >= ) {
indexPressWord.setIndexPressWord(words[index]);
}
invalidate();
break;
case MotionEvent.ACTION_UP:
index = -;
invalidate();
break;
default:
}
return true;
}
當某個子母被點選或者滑到的時候,通過index = (int) (event.getY() / everyheght)得到他是哪個字幕,也就是下标,然後調用invalidate()方法重走onDraw方法,在通過if判斷,如果點選的是這個字幕 改變 畫筆的顔色,這樣就實作了效果。
3.中間正方形字幕的實作
其實,上一步重寫onTouchEvent的時候我們已經得到了點選的字幕,這個時候我們隻是要把他在正方形中呈現出來而已,那麼就很容易實作了,直接通過接口會調就實作了,上一步驟中已經給出了回調:indexPressWord.setIndexPressWord(words[index]),直接在主線程中就可以set出來,讓正方形出現三秒再消失,這裡的方法有很多很多,我用的是handler,下面是主要代碼:
private void setTvWord() {
iwMain.setIndexPressWord(new IndexWord.IndexPressWord() {
@Override
public void setIndexPressWord(String word) {
tvMain.setVisibility(View.VISIBLE);
tvMain.setText(word);
handler.postDelayed(new Runnable() {
@Override
public void run() {
tvMain.setVisibility(View.GONE);
}
}, );
}
});
}
一看應該就會很明白了
4.Recycleview呈現資料源,以及跳到制定字幕的實作
這裡就不貼代碼了,說一下實作思路,還是看張圖檔:
全是套路,哈哈,隻是把那些不該看到的東西隐藏掉了而已,當然如果覺得自己很牛叉,可以試試recycleview的多布局,保證會寫吐。
這裡的阿虎阿貓以及A、B是Perdon類的屬性;Person類如下:
public class Person {
private String name;
private String pinyin;
public Person(String name){
this.name = name;
this.pinyin = PinYinUtils.getPinYin(name);
}
代碼中的PersonUtils是專門把漢子轉換為拼音的工具類,我們截取拼音的第一位就得到了A、B,很容易。
具體如何判斷某個字母是不是第一次出現,待會兒可以看下源碼,很容易了解,這裡就不貼代碼了。
5.實作點選右側字母,聯系人自動移到對應聯系人
其實和中間的正方形顯示字幕一個意思,同樣是在回調裡面實作,回掉裡面拿到字幕Word,然後周遊persons,如果person拼音的首位與word相同,那麼記錄下位置i,然後移動就可以了,主要代碼如下:
private void getWord(String word) {
for (int i = ; i < persons.size(); i++) {
String substring = persons.get(i).getPinyin().substring(, );
if (substring.equals(word) && persons.size() >= i) {
//如果person拼音的首位與word相同,則實作效果,并退出循環
View childAt = rvMain.getChildAt(i);
MoveToPosition(linearmanger, rvMain, i);
break;
}
}
}
/**
* 此方法是讓recycleview滑動到指定位置,并且是讓其到頂部
*
* @param manager
* @param mRecyclerView
* @param n
*/
public void MoveToPosition(LinearLayoutManager manager, RecyclerView mRecyclerView, int n) {
int firstItem = manager.findFirstVisibleItemPosition();
int lastItem = manager.findLastVisibleItemPosition();
if (n <= firstItem) {
mRecyclerView.scrollToPosition(n);
} else if (n <= lastItem) {
int top = mRecyclerView.getChildAt(n - firstItem).getTop();
mRecyclerView.scrollBy(, top);
} else {
mRecyclerView.scrollToPosi
tion(n);
}
}
這樣就簡單實作了聯系人快速定位的功能,有問題請加QQ群661614986,點選檢視源碼。