模仿通讯录按字母分类显示,汉字,英文自动按英文字母分类显示,滑动时用气泡显示最上面的汉字首字母提示,右侧字母栏点击快速定位

来源:互联网 发布:蓝犀牛搬家 知乎 编辑:程序博客网 时间:2024/05/03 22:10

废话不多说,先上图。

 

本Demo实现了如下功能:

1.根据汉字首字母,自动按英文字母分类显示。

2.滑动时,泡泡显示最上面的汉字首字母提示。

3.右侧字母栏点击快速定位,方便多数据的查找定位。

不足之处:

1.汉字转化得到拼音首字母的时候,我用到了一个pinyin4j-2.5.0.jar包,多音字和某些特殊汉字翻译不准确,如:我发现厦门,它会翻译成shamen,结果首字母变成了s。

   结果我只好特殊处理了,朋友们有好的解决办法的话麻烦分享一下。

好了,废话不说了,上代码,总共3.java文件和3个配置文件。

(1)Main.java

package com.lmj.quickaction;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import com.lmj.quickaction.RightCharacterListView.OnTouchingLetterChangedListener;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

/**
 * @author lmj
 */
public class Main extends Activity implements ListView.OnScrollListener,
  OnItemClickListener, android.view.View.OnClickListener {
 private RightCharacterListView letterListView;
 private Handler handler;
 private DisapearThread disapearThread;
 private int scrollState;
 private ListAdapter listAdapter;
 private ListView listMain;
 private TextView txtOverlay;
 private WindowManager windowManager;

 private String[] stringArr = { "阿拉伯", "阿镇", "阿布", "北京", "北城", "成", "城市",
   "得", "额", "方", "搞", "广州", "黄石", "黄冈", "杭州", "上海", "上饶", "厦门", "深圳",
   "武林", "武林", "武林", "武林", "武林", "武林", "武林", "武林", "武林", "武林", "武林",
   "武林", "武林", "武林", "武林", "武汉", "下午", "责打", "浙江", "浙江", "浙江", "浙江",
   "浙江", "浙江", "浙江", "浙江", "浙江", "浙江", "浙江", "浙江", "浙江", "浙江", "浙江",
   "浙江", "浙江", "浙江", "浙江", "浙江", "浙江" };

 private String[] stringArr3 = new String[0];
 private ArrayList arrayList = new ArrayList();
 private ArrayList arrayList2 = new ArrayList();
 private ArrayList arrayList3 = new ArrayList();
 private Map<String, String> map = new HashMap<String, String>();

 public String converterToPinYin(String chinese) {
  String pinyinString = "";
  char[] charArray = chinese.toCharArray();
  // 根据需要定制输出格式,我用默认的即可
  HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
  try {
   // 遍历数组,ASC码大于128进行转换
   for (int i = 0; i < charArray.length; i++) {
    if (charArray[i] > 128) {
     // charAt(0)取出首字母
     pinyinString += PinyinHelper.toHanyuPinyinStringArray(
       charArray[i], defaultFormat)[0].charAt(0);
    } else {
     pinyinString += charArray[i];
    }
   }
   return pinyinString;
  } catch (BadHanyuPinyinOutputFormatCombination e) {
   e.printStackTrace();
   return null;
  }
 }

 public class LetterListViewListener implements
   OnTouchingLetterChangedListener {

  @Override
  public void onTouchingLetterChanged(final String s) {

   Toast.makeText(Main.this, s, Toast.LENGTH_LONG).show();
   int num = 0;
   for (int i = 0; i < stringArr.length; i++) {
    if ("a".equals(s)) {
     num = 0;
    } else if (character2ASCII(stringArr[i].substring(0, 1)) < (character2ASCII(s) + 32)) {
     num += 1;
    }

   }

   listMain.setSelectionFromTop(num, 0);
   // .setSelection(num);

  }

 }

 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  for (int i = 0; i < stringArr.length; i++) {
   String pinyin = converterToPinYin(stringArr[i]);
   arrayList.add(pinyin);
   if (!arrayList2.contains(pinyin.substring(0, 1))) {
    arrayList2.add(pinyin.substring(0, 1));
   }
   map.put(pinyin, stringArr[i]);
  }
  stringArr = (String[]) arrayList.toArray(stringArr);

  arrayList3.add("#");
  for (int i = 0; i < arrayList2.size(); i++) {
   String string = (String) arrayList2.get(i);
   arrayList3.add(string.toUpperCase());
  }

  stringArr3 = (String[]) arrayList3.toArray(stringArr3);// 得到右侧英文字母列表

  letterListView = (RightCharacterListView) findViewById(R.id.rightCharacterListView);

  String[] b = { "#", "A", "B", "C", "D", "E", "F", "G", "H", "S", "W",
    "X", "Z" };
  letterListView.setB(stringArr3);

  letterListView
    .setOnTouchingLetterChangedListener(new LetterListViewListener());

  handler = new Handler();
  // 初始化首字母悬浮提示框
  txtOverlay = (TextView) LayoutInflater.from(this).inflate(
    R.layout.popup_char, null);
  txtOverlay.setVisibility(View.INVISIBLE);
  WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
    LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
    WindowManager.LayoutParams.TYPE_APPLICATION,
    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
      | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
    PixelFormat.TRANSLUCENT);
  windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
  windowManager.addView(txtOverlay, lp);
  // 初始化ListAdapter
  listAdapter = new ListAdapter(this, stringArr, this, map);
  listMain = (ListView) findViewById(R.id.listInfo);
  listMain.setOnItemClickListener(this);
  listMain.setOnScrollListener(this);
  listMain.setAdapter(listAdapter);
  disapearThread = new DisapearThread();
 }

 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
  // txtOverlay.setText(String.valueOf(stringArr[firstVisibleItem +
  // (visibleItemCount >> 1)]
  // .charAt(0)));//泡泡文字以中间的显示为准

  txtOverlay
    .setText(String.valueOf(stringArr[firstVisibleItem].charAt(0)));// 泡泡文字以第一个可见列表为准
 }

 public void onScrollStateChanged(AbsListView view, int scrollState) {
  this.scrollState = scrollState;
  if (scrollState == ListView.OnScrollListener.SCROLL_STATE_IDLE) {
   handler.removeCallbacks(disapearThread);
   // 提示延迟1.5s再消失
   boolean bool = handler.postDelayed(disapearThread, 1500);
  } else {
   txtOverlay.setVisibility(View.VISIBLE);
  }
 }

 public void onItemClick(AdapterView<?> parent, View view, int position,
   long id) {
  // String personalName = stringArr[position];
  String personalName = map.get(stringArr[position]);
 }

 public void onClick(View view) {

 }

 private class DisapearThread implements Runnable {
  public void run() {
   // 避免在1.5s内,用户再次拖动时提示框又执行隐藏命令。
   if (scrollState == ListView.OnScrollListener.SCROLL_STATE_IDLE) {
    txtOverlay.setVisibility(View.INVISIBLE);
   }
  }
 }

 public void onDestroy() {
  super.onDestroy();
  // 将txtOverlay删除。
  txtOverlay.setVisibility(View.INVISIBLE);
  windowManager.removeView(txtOverlay);
 }

 /**
  * 把单个英文字母或者字符串转换成数字ASCII码
  *
  * @param input
  * @return
  */
 public static int character2ASCII(String input) {
  char[] temp = input.toCharArray();
  StringBuilder builder = new StringBuilder();
  for (char each : temp) {
   builder.append((int) each);
  }
  String result = builder.toString();
  return Integer.parseInt(result);
 }
}

 

(2)ListAdapter,列表适配器

package com.lmj.quickaction;

import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * @author lmj
 * 列表适配器
 */
public class ListAdapter extends BaseAdapter {
 private LayoutInflater layoutInflater;
 private OnClickListener onClickListener;
 private String[] stringArr;
 private Map<String, String> map = new HashMap<String, String>();

 public ListAdapter(Context context, String[] arr, OnClickListener listener,Map<String, String> map) {
  layoutInflater = LayoutInflater.from(context);
  this.onClickListener = listener;
  stringArr = arr;
  this.map = map;
 }

 public int getCount() {
  return stringArr == null ? 0 : stringArr.length;
 }

 public Object getItem(int position) {
 
  Log.d("position", position+"--->"+stringArr[position]);
 
  if (stringArr != null) {
   String string = map.get(stringArr[position]);
   return string;
  }
  return null;
 }

 public long getItemId(int position) {
  return position;
 }

 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder = null;
  if (convertView == null) {
   convertView = layoutInflater.inflate(R.layout.list_item, null);
   holder = new ViewHolder();
   holder.firstCharHintTextView = (TextView) convertView
     .findViewById(R.id.text_first_char_hint);
   holder.nameTextView = (TextView) convertView.findViewById(R.id.text_website_name);
   convertView.setTag(holder);
  } else {
   holder = (ViewHolder) convertView.getTag();
  }
  holder.nameTextView.setText(map.get(stringArr[position]));
  int idx = position - 1;
  char previewChar = idx >= 0 ? stringArr[idx].charAt(0) : ' ';
  char currentChar = stringArr[position].charAt(0);
  if (currentChar != previewChar) {
   holder.firstCharHintTextView.setVisibility(View.VISIBLE);
   holder.firstCharHintTextView.setText(String.valueOf(currentChar));
  } else {
   //实例化一个CurrentView后,会被多次赋值并且只有最后一次赋值的position是正确
   holder.firstCharHintTextView.setVisibility(View.GONE);
  }
  return convertView;
 }

 public final class ViewHolder {
  public TextView firstCharHintTextView;
  public TextView nameTextView;
 }
}

(3)RightCharacterListView,右侧字母表,快速定位

package com.lmj.quickaction;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 右侧字母表,快速定位
 * @author lmj
 *
 */
public class RightCharacterListView extends View {
 private String[] b = null;

 public void setB(String[] b) {
  this.b = b;
 }

 OnTouchingLetterChangedListener onTouchingLetterChangedListener;
// String[] b = {"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" };
 
// String[] b = {"A", "B", "C", "D", "E", "F", "G", "H", "S", "W", "X",
//   "Z" };
 int choose = -1;
 Paint paint = new Paint();
 boolean showBkg = false;

 public RightCharacterListView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
 }

 public RightCharacterListView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

 public RightCharacterListView(Context context) {
  super(context);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  if (showBkg) {
   canvas.drawColor(Color.parseColor("#40000000"));
  }

  int height = getHeight();
  int width = getWidth();
  int singleHeight = height / b.length;
  for (int i = 0; i < b.length; i++) {
   paint.setColor(Color.WHITE);
   paint.setTypeface(Typeface.DEFAULT_BOLD);
   paint.setAntiAlias(true);
   if (i == choose) {
    paint.setColor(Color.parseColor("#3399ff"));
    paint.setFakeBoldText(true);
   }
   float xPos = width / 2 - paint.measureText(b[i]) / 2;
   float yPos = singleHeight * i + singleHeight;
   canvas.drawText(b[i], xPos, yPos, paint);
   paint.reset();
  }

 }

 @Override
 public boolean dispatchTouchEvent(MotionEvent event) {
  final int action = event.getAction();
  final float y = event.getY();
  final int oldChoose = choose;
  final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
  final int c = (int) (y / getHeight() * b.length);

  switch (action) {
  case MotionEvent.ACTION_DOWN:
   showBkg = true;
   if (oldChoose != c && listener != null) {
    if (c >0 && c < b.length) { //如果第一个字母是#,无效点击的话,条件变为c>0
     listener.onTouchingLetterChanged(b[c]);
     choose = c;
     invalidate();
    }
   }

   break;
  case MotionEvent.ACTION_MOVE:
   if (oldChoose != c && listener != null) {
    if (c >0 && c < b.length) {  //如果第一个字母是#,无效点击的话,条件变为c>0
     listener.onTouchingLetterChanged(b[c]);
     choose = c;
     invalidate();
    }
   }
   break;
  case MotionEvent.ACTION_UP:
   showBkg = false;
   choose = -1;
   invalidate();
   break;
  }
  return true;
 }

 @Override
 public boolean onTouchEvent(MotionEvent event) {
  return super.onTouchEvent(event);
 }

 public void setOnTouchingLetterChangedListener(
   OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
  this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
 }

 public interface OnTouchingLetterChangedListener {
  public void onTouchingLetterChanged(String s);
 }

}

(4)main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
 <ListView android:id="@+id/listInfo"   
         android:focusable="true"   
         android:layout_weight="1.0"   
         android:layout_height="wrap_content"   
         android:layout_width="fill_parent"   
         android:fastScrollEnabled="true" 
         android:cacheColorHint="#00000000" 
         android:background="@drawable/background"   
     >
    </ListView>
   
    <com.lmj.quickaction.RightCharacterListView
     android:id="@+id/rightCharacterListView"
  android:background="#40000000"
  android:layout_width="30dip"
  android:layout_height="fill_parent"
  android:layout_alignParentRight="true" />
 
</RelativeLayout>
(5)list_item.xml<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:id="@+id/list_item_parent_layout"
 >
 <TextView android:id="@+id/text_first_char_hint"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:textSize="@dimen/list_first_char_hint_text_size"
  android:background="@color/char_color"
  android:textColor="@*android:color/dim_foreground_light"
  android:paddingLeft="@dimen/list_item_first_char_padding"
  android:visibility="gone">
 </TextView>
 
 <LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  <LinearLayout
   android:orientation="vertical"
   android:layout_width="wrap_content"
   android:layout_height="fill_parent"
   android:layout_weight="1">
   <TextView android:id="@+id/text_website_name"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textColor="@android:color/white"
    android:textSize="@dimen/list_item_name_size"
    android:singleLine="true"
         android:ellipsize="marquee"
   ></TextView>
  </LinearLayout>
  <View android:id="@+id/divider"
   android:background="@*android:color/dim_foreground_dark"
   android:focusable="false"
   android:clickable="false"
   android:longClickable="false"
   android:layout_marginTop="@dimen/list_item_divider_margin"
   android:layout_marginBottom="@dimen/list_item_divider_margin"
   android:layout_width="1dp"
   android:layout_height="fill_parent"
   android:gravity="center_vertical"
  ></View>
 </LinearLayout>
</LinearLayout>

(6)popup_char.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:textSize="@dimen/popup_char_min_length"
    android:textColor="@android:color/white"
    android:background="@color/popup_char_color"
    android:minWidth="@dimen/popup_char_min_length"
    android:maxWidth="@dimen/popup_char_min_length"
    android:gravity="center"
/>

(7)dimension.xml,资源文件

<?xml version="1.0" encoding="UTF-8"?>
<resources>
 <dimen name="list_first_char_hint_text_size">15sp</dimen>
 <dimen name="list_item_order_number_size">30sp</dimen>
 <dimen name="list_item_first_view_right_margin">30sp</dimen>
 <dimen name="list_item_first_char_padding">10dip</dimen>
 <dimen name="list_item_name_size">25sp</dimen>
 <dimen name="list_item_divider_margin">5dip</dimen>
 <dimen name="list_item_icon_length">50sp</dimen>
 <dimen name="popup_char_min_length">70dip</dimen>
</resources>

还有string.xml和color.xml就不贴了,也就几个,缺啥就补啥。

好了,今天就到这吧,朋友们有啥问题的给我留言,只要我能解决的,一定告诉大家。

以为写个博客就10分钟的事情,实际上我用了一个小时,oh,My God!!

不过要是有人能用的上,我的时间也算是有所值了,呵呵。

有问题欢迎讨论,还望各位口下留情。

 忘了,还缺了个图片:

和第三方jar包pinyin4j-2.5.0,jar包自己下吧,呵呵。

 

源码下载:http://download.csdn.net/detail/nicholas6lee/4355391

原创粉丝点击