先看看图片效果,我的是来源于网上资料的改进,希望帮助对这方面有需要的的朋友
直接上图上代码,就不解释了,最底部有代码下载链接,想要的童鞋就去下吧
下载地址:http://download.csdn.net/detail/touchsnow/5349469
实现的功能:混合字符串处理 中英文排序 右侧悬浮栏 顶部名称提示栏 滚动悬浮提示
图
一 右侧字母表工具
package com.zuo.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 zuo
* @email 782287169@qq.com
*/
public class QuickLocationRightTool extends View
{
private String[] b = null;
public void setB(String[] b)
{
this.b = b;
}
OnTouchingLetterChangedListener onTouchingLetterChangedListener;
int choose = -1;
Paint paint = new Paint();
boolean showBkg = false;
public QuickLocationRightTool(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
public QuickLocationRightTool(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public QuickLocationRightTool(Context context)
{
super(context);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (showBkg) {
canvas.drawColor(Color.parseColor("#10000000"));
}
int height = getHeight();
int width = getWidth();
int singleHeight = height / b.length;
for (int i = 0; i < b.length; i++) {
paint.setColor(Color.BLACK);
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);
}
}
二 分组排序的列表适配器
package com.zuo.quickaction; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author zuo * 列表适配器 */ public class QuickLocationListAdapter extends BaseAdapter { private LayoutInflater layoutInflater; private OnClickListener onClickListener; private String[] stringArr; private Map<String, String> map = new HashMap<String, String>(); public QuickLocationListAdapter(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) { 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) { //如果不相等时显示 if (isWord(currentChar)) { if (position != 0) { holder.firstCharHintTextView.setVisibility(View.VISIBLE); } else { holder.firstCharHintTextView.setVisibility(View.GONE); } holder.firstCharHintTextView.setText(String.valueOf(currentChar)); } else { if (isWord(previewChar)) { holder.firstCharHintTextView.setVisibility(View.VISIBLE); holder.firstCharHintTextView.setText("*"); } else { holder.firstCharHintTextView.setVisibility(View.GONE); } } } else { holder.firstCharHintTextView.setVisibility(View.GONE); } return convertView; } public final class ViewHolder { public TextView firstCharHintTextView; public TextView nameTextView; } public boolean isWord(char c) { Pattern pattern = Pattern.compile("^[A-Za-z]+$"); Matcher isNum = pattern.matcher(String.valueOf(c)); if (!isNum.matches()) { return false; } else { return true; } } }
三 主函数
package com.zuo.quickaction; import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; import android.os.Bundle; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.view.WindowManager; import android.widget.*; import android.widget.AdapterView.OnItemClickListener; import com.zuo.quickaction.QuickLocationRightTool.OnTouchingLetterChangedListener; import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author zuowen * @time 2013.05.08 * @email 782287169@qq.com * <p/> * 混合字符串处理 中英文排序 右侧悬浮栏 顶部名称提示栏 滚动悬浮提示 */ public class QuickLocationMainActivity extends Activity implements ListView.OnScrollListener, OnItemClickListener, android.view.View.OnClickListener { private QuickLocationRightTool letterListView; private Handler handler; private DisapearThread disapearThread; private int scrollState; private QuickLocationListAdapter quickLocationListAdapter; private ListView listMain; private TextView txtOverlay, title; private WindowManager windowManager; private String[] stringArr = {"ai", "zuo", "wn", "g黄真伊", "he河智苑", "@", "&&*(*", "한국 친구를 찾아요", "?", "擬好", "上饶", "厦门", "深圳", "武林", "text1", "+*())*&%$^", "11112", "6666", "898和", "阿拉伯", "阿镇", "下午", "责打", "浙江", "浙江", "阿布", "北京", "北城", "成", "城市", "123a", "234b", "678c", "得", "额", "方", "搞", "广州", "黄石", "黄冈", "杭州", "上海", "武林"}; 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 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); //此列表增加拼音 Collections.sort(arrayList, new MixComparator()); if (!arrayList2.contains(pinyin.substring(0, 1)) && isWord(pinyin.substring(0, 1))) { arrayList2.add(pinyin.substring(0, 1)); //此列表添加拼音首字母 Collections.sort(arrayList2, new MixComparator()); } 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()); //toUpperCase大写字母 } arrayList3.add("*"); stringArr3 = (String[]) arrayList3.toArray(stringArr3); // 得到右侧英文字母列表 letterListView = (QuickLocationRightTool) findViewById(R.id.rightCharacterListView); letterListView.setB(stringArr3); letterListView.setOnTouchingLetterChangedListener(new LetterListViewListener()); textOverlayout(); // 初始化ListAdapter quickLocationListAdapter = new QuickLocationListAdapter(this, stringArr, this, null); listMain = (ListView) findViewById(R.id.listInfo); listMain.setOnItemClickListener(this); listMain.setOnScrollListener(this); listMain.setAdapter(quickLocationListAdapter); disapearThread = new DisapearThread(); } /** * 滚到悬浮字母 */ public void textOverlayout() { handler = new Handler(); //顶部悬浮 title = (TextView) findViewById(R.id.list_title); // 初始化首字母悬浮提示框 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); } /** * 右侧导航条点击列表滚动指定位置 */ public class LetterListViewListener implements OnTouchingLetterChangedListener { public void onTouchingLetterChanged(final String s) { int num = 0; for (int i = 0; i < stringArr.length; i++) { if ("a".equals(s) || "#".equals(s)) { //顶部 num = 0; } else if ("*".equals(s)) { //底部 num = stringArr.length; } else if (isWord(stringArr[i].substring(0, 1)) && (character2ASCII(stringArr[i].substring(0, 1)) < (character2ASCII(s) + 32))) { num += 1; //首先判断是字母,字母的ascll值小于s是,滚动位置+1;如果有10个数据小于s,就滚到10处 } } if (num < 2) { listMain.setSelectionFromTop(num, 0); } else { listMain.setSelectionFromTop(num, 5); //留点间隔 } } } /** * 滚动处理 * @param view * @param firstVisibleItem * @param visibleItemCount * @param totalItemCount */ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { title.setVisibility(View.VISIBLE); if (firstVisibleItem != 0) { title.setText(map.get(stringArr[firstVisibleItem])); } else { title.setText("a"); } title.setText(map.get(stringArr[firstVisibleItem])); 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.0s再消失 boolean bool = handler.postDelayed(disapearThread, 1000); } else { txtOverlay.setVisibility(View.VISIBLE); } } /** * 列表点击 * @param parent * @param view * @param position * @param id */ public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String personalName = map.get(stringArr[position]); Toast.makeText(QuickLocationMainActivity.this, personalName, 1).show(); } 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.setVisibility(View.INVISIBLE); title.setVisibility(View.INVISIBLE); windowManager.removeView(txtOverlay); } /** * 汉语拼音转换工具 * * @param chinese * @return */ 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)取出首字母 if (charArray[i] >= 0x4e00 && charArray[i] <= 0x9fa5) { //判断是否中文 pinyinString += PinyinHelper.toHanyuPinyinStringArray( charArray[i], defaultFormat)[0].charAt(0); } else { //不是中文的打上未知,所以无法处理韩文日本等等其他文字 pinyinString += "?"; } } else { pinyinString += charArray[i]; } } return pinyinString; } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); return null; } } /** * 把单个英文字母或者字符串转换成数字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); } /** * 混合排序工具 */ public class MixComparator implements Comparator<String> { public int compare(String o1, String o2) { // 判断是否为空"" if (isEmpty(o1) && isEmpty(o2)) return 0; if (isEmpty(o1)) return -1; if (isEmpty(o2)) return 1; String str1 = ""; String str2 = ""; try { str1 = (o1.toUpperCase()).substring(0, 1); str2 = (o2.toUpperCase()).substring(0, 1); } catch (Exception e) { System.out.println("某个str为\" \" 空"); } if (isWord(str1) && isWord(str2)) { //字母 return str1.compareTo(str2); } else if (isNumeric(str1) && isWord(str2)) { //数字字母 return 1; } else if (isNumeric(str2) && isWord(str1)) { return -1; } else if (isNumeric(str1) && isNumeric(str2)) { //数字数字 if (Integer.parseInt(str1) > Integer.parseInt(str2)) { return 1; } else { return -1; } } else if (isAllWord(str1) && (!isAllWord(str2))) { //数字字母 其他字符 return -1; } else if ((!isAllWord(str1)) && isWord(str2)) { return 1; } else { return 1; } } } /** * 判断空 * * @param str * @return */ private boolean isEmpty(String str) { return "".equals(str.trim()); } /** * 判断数字 * * @param str * @return */ public boolean isNumeric(String str) { Pattern pattern = Pattern.compile("^[0-9]*$"); Matcher isNum = pattern.matcher(str); if (!isNum.matches()) { return false; } else { return true; } } /** * 判读字母 * * @param str * @return */ public boolean isWord(String str) { Pattern pattern = Pattern.compile("^[A-Za-z]+$"); Matcher isNum = pattern.matcher(str); if (!isNum.matches()) { return false; } else { return true; } } /** * 判断字母数字混合 * * @param str * @return */ public boolean isAllWord(String str) { Pattern pattern = Pattern.compile("^[A-Za-z0-9]+$"); Matcher isNum = pattern.matcher(str); if (!isNum.matches()) { return false; } else { return true; } } }
四 xml文件
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="18dp" android:padding="5dp" android:background="#e1e1e1" android:textColor="#f00" 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/black" android:textSize="14dp" android:singleLine="true" android:padding="8dp" android:text="android" /> </LinearLayout> <View android:id="@+id/divider" android:background="#ccc" android:focusable="false" android:clickable="false" android:longClickable="false" android:layout_marginTop="5dp" android:layout_marginBottom="5dp" android:layout_width="1dp" android:layout_height="fill_parent" android:gravity="center_vertical" /> </LinearLayout> </LinearLayout>
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" > <TextView android:id="@+id/list_title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="18dp" android:padding="5dp" android:background="#e1e1e1" android:textColor="#f00" android:text="a" android:layout_alignParentTop="true" android:visibility="gone"> </TextView> <ListView android:id="@+id/listInfo" android:layout_below="@id/list_title" android:focusable="true" android:layout_weight="1.0" android:layout_height="match_parent" android:layout_width="fill_parent" android:scrollbars="none" android:cacheColorHint="#00000000" android:background="#fff" > </ListView> <com.zuo.quickaction.QuickLocationRightTool android:id="@+id/rightCharacterListView" android:background="#08000000" android:layout_width="20dip" android:layout_height="fill_parent" android:layout_alignParentRight="true"/> </RelativeLayout>