废话不多说,先上图。
本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