自定義快速查找字母控件

效果圖以下:android

首先看看佈局文件,自定義的控件中包含一個 ListView,用於顯示具體的數據內容:canvas

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginTop="20dp"
    android:background="#fffafafa"
    android:orientation="vertical" >
    <com.common.myletterview.LetterFilterListView
        android:id="@+id/letterView"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent" >
        <ListView
            android:id="@+id/listView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:cacheColorHint="#00000000"
            android:divider="@null"/>
    </com.common.myletterview.LetterFilterListView>
</LinearLayout>

加載完 xml 中的 View 後,在自定義控件中添加靠右顯示的一列字母控件、點擊那列字母后的顯示字母控件,這兩個子控件均繼承自 View,均採用自繪。ide

右邊一列字母顯示控件的繪製以下:佈局

/**
   * 初始化.
   */
  private void init() {
   mLetters = new char[] { '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', '#' };
   mPaint = new Paint();
   mPaint.setColor(Color.parseColor("#949494"));
   mPaint.setTypeface(Typeface.DEFAULT_BOLD);
   mPaint.setTextSize(22);
   mPaint.setAntiAlias(true);
   mPaint.setTextAlign(Paint.Align.CENTER);
  }
  @Override
  protected void onDraw(Canvas canvas) {
   super.onDraw(canvas);
   float height = getHeight();
   mSingleHeight = height / mLetters.length;
   mWidthCenter = getMeasuredWidth() / (float) 2;
   for (int i = 0; i < mLetters.length; i++) {
    canvas.drawText(String.valueOf(mLetters[i]), mWidthCenter, mSingleHeight + (i * mSingleHeight), mPaint);
   }
  }

 

自定義實體實現每項內容與內容首字母的捆綁:post

public class Letter implements Comparable<Letter> {
 private int id;
 private String name;//名字
 private String firstLetter;//名字首字母
 
 public Letter() {
  super();
 }
 public Letter(int id, String name, String firstLetter) {
  super();
  this.id = id;
  this.name = name;
  this.firstLetter = firstLetter;
 }
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public String getFirstLetter() {
  return firstLetter;
 }
 public void setFirstLetter(String firstLetter) {
  this.firstLetter = firstLetter;
 }
 
 @Override
 public int compareTo(Letter another) {
  if (this.getFirstLetter().equals("@")
    || another.getFirstLetter().equals("#")) {
   return -1;
  } else if (this.getFirstLetter().equals("#")
    || another.getFirstLetter().equals("@")) {
   return 1;
  } else {
   return this.getFirstLetter().compareTo(another.getFirstLetter());
  }
 }
}

適配器實現 SectionIndexer 接口,接口中的兩個方法實現是關鍵,具體以下:this

 /**
  * 根據ListView的當前位置獲取分類的首字母的Char ascii值
  */
 public int getSectionForPosition(int position) {
  return mList.get(position).getFirstLetter().charAt(0);
 }
 /**
  * 根據分類的首字母的Char ascii值獲取其第一次出現該首字母的位置
  */
 public int getPositionForSection(int section) {
  for (int i = 0; i < getCount(); i++) {
   String sortStr = mList.get(i).getFirstLetter();
   char firstChar = sortStr.toUpperCase().charAt(0);
   if (firstChar == section) {
    return i;
   }
  }
  return -1;
 }

適配器每一個 Item 包括字母行跟內容行,若是當前位置等於該分類首字母的Char的位置 ,則顯示字母行跟內容行,不然只顯示出內容行,具體代碼以下:.net

 //根據position獲取分類的首字母的Char ascii值
  int section = getSectionForPosition(position);
  
  //若是當前位置等於該分類首字母的Char的位置 ,則認爲是第一次出現
  if(position == getPositionForSection(section)){
   viewHolder.tvLetter.setVisibility(View.VISIBLE);
   viewHolder.tvLetter.setText(letter.getFirstLetter());
  }else{
   viewHolder.tvLetter.setVisibility(View.GONE);
  }

在點擊右邊字母列表的時候,根據點擊的位置從新計算點擊了那個字母,從而做相應的定位,並顯示選中的字母:code

 public boolean onTouchEvent(MotionEvent event) {
   super.onTouchEvent(event);
   int index = 0;//點擊的位置在 mLetters 中的索引
   int i = (int) event.getY();
   int div = (int) mSingleHeight;
   /** 從新計算出索引 */
   if (div != 0) {
    index = i / div;
   }
   if (index >= mLetters.length) {
    index = mLetters.length - 1;
   } else if (index < 0) {
    index = 0;
   }
   switch (event.getAction()) {
   case MotionEvent.ACTION_UP:
    break;
   case MotionEvent.ACTION_DOWN:
   case MotionEvent.ACTION_MOVE:
    mLetterSelectedView.setViewY(mSingleHeight + (index * mSingleHeight));//設置選中字母顯示的y軸位置
    mLetterSelectedView.setSelectedLetter(mLetters[index]);//設置選中的字母
    if (mLetterSelectedView.getVisibility() == View.GONE)//若控件爲隱藏狀態,則顯示
     mLetterSelectedView.setVisibility(View.VISIBLE);
    /** 顯示1s後消失*/
    mLetterSelectedView.postDelayed(new Runnable() {
     @Override
     public void run() {
      // TODO Auto-generated method stub
      mLetterSelectedView.setVisibility(View.GONE);
     }
    }, 1000);
    
    if (mListView.getAdapter() != null) {
     ListAdapter listAdapter = (ListAdapter) mListView.getAdapter();
     if (mSectionIndexter == null) {
      mSectionIndexter = (SectionIndexer) listAdapter;
     }
     int position = mSectionIndexter.getPositionForSection(mLetters[index]);
     if (position == -1) {//列表中沒有首字母爲選中字母的的項
      return true;
     }
     mListView.setSelection(position);
    }
   }
   return true;
  }

僅僅看此博客可能很難理解具體的實現,你們能夠結合完整的代碼查看,完整代碼:自定義快速查找字母控件xml

最近在運營一個有關反脆弱成長的我的公衆號,歡迎關注繼承

相關文章
相關標籤/搜索