码迷,mamicode.com
首页 > 其他好文 > 详细

自定义快速查找字母控件

时间:2015-03-16 23:19:23      阅读:341      评论:0      收藏:0      [点我收藏+]

标签:

效果图如下:

技术分享

首先看看布局文件,自定义的控件中包含一个 ListView,用于显示具体的数据内容:

<?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,均采用自绘。

右边一列字母显示控件的绘制如下:

/**
   * 初始化.
   */
  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);
   }
  }

 

自定义实体实现每项内容与内容首字母的捆绑:

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 接口,接口中的两个方法实现是关键,具体如下:

 /**
  * 根据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的位置 ,则显示字母行跟内容行,否则只显示出内容行,具体代码如下:

 //根据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);
  }

在点击右边字母列表的时候,根据点击的位置重新计算点击了那个字母,从而作相应的定位,并显示选中的字母:

 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;
  }

仅仅看此博客可能很难理解具体的实现,大家可以结合完整的代码查看,完整代码:自定义快速查找字母控件

自定义快速查找字母控件

标签:

原文地址:http://my.oschina.net/u/1460984/blog/387705

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!