ListView字母快速索引 自动搜索

最近先来没事,提取一下项目中的一些实用性功能,也算是一种知识总结。希望对自己和需要此功能的朋友有一些帮助


效果图:

字母索引


过滤搜索


功能代码:

自定义一个字母索引的View

MyLetterListView.java

package com.pz.filter.view;

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;

public class MyLetterListView extends View {

	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" };
	int choose = -1;
	Paint paint = new Paint();
	boolean showBkg = false;

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

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

	public MyLetterListView(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) {
					listener.onTouchingLetterChanged(b[c]);
					choose = c;
					invalidate();
				}
			}

			break;
		case MotionEvent.ACTION_MOVE:
			if (oldChoose != c && listener != null) {
				if (c > 0 && c < b.length) {
					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);
	}

}

主类PzFilterActivity.java

package com.pz.filter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

import android.app.Activity;
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.graphics.PixelFormat;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.pz.filter.view.MyLetterListView;
import com.pz.filter.view.MyLetterListView.OnTouchingLetterChangedListener;

public class PzFilterActivity extends Activity {
	private static final String TAG = "PzFilterActivity";

	private Button queryBtn;// 查询按钮
	private EditText queryContent;// 查询条件
	private ListView listView;// listView显示查询结果
	private AsyncQueryHandler asyncQuery;
	private HashMap<String, Integer> alphaIndexer;
	private Handler handler;
	private OverlayThread overlayThread;
	private TextView overlay;// 显示索引字母
	private MyLetterListView letterListView;
	private ArrayList<Contact> mListLocalContact;
	private TextWatcher textWatcher = new MyFindContactTextWatcher();
	private OnItemClickListener itemClickListener = new MyListItemClickListener();
	private OnItemLongClickListener itemLongClickListener = new MyOnItemLongClickListener();
	private OnClickListener clickListener = new MyOnClickListener();

	public String[] sections;

	private ListAdapter adapter;

	private boolean queryFlag = true;
	private List<Contact> queryList = new ArrayList<Contact>();

	public boolean overlayFlag = true;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		initwidget();
		listView.setOnItemClickListener(itemClickListener);
		listView.setOnItemLongClickListener(itemLongClickListener);
		queryBtn.setOnClickListener(clickListener);

		letterListView = (MyLetterListView) findViewById(R.id.MyLetterListView01);
		letterListView
				.setOnTouchingLetterChangedListener(new LetterListViewListener());

		asyncQuery = new MyAsyncQueryHandler(getContentResolver());
		alphaIndexer = new HashMap<String, Integer>();
		handler = new Handler();
		overlayThread = new OverlayThread();
		queryContent.addTextChangedListener(textWatcher);

	}

	/**
	 * 初始化部件
	 */
	private void initwidget() {
		queryBtn = (Button) findViewById(R.id.queryBtn);
		queryContent = (EditText) findViewById(R.id.queryContent);
		listView = (ListView) findViewById(R.id.listview);
	}

	@Override
	protected void onResume() {
		super.onResume();
		Uri uri = Uri.parse("content://com.android.contacts/data/phones");
		String[] projection = { "_id", "display_name", "data1", "sort_key" };
		asyncQuery.startQuery(0, null, uri, projection, null, null,
				"sort_key COLLATE LOCALIZED asc");
	}

	private void setAdapter(List<Contact> list) {
		adapter = new ListAdapter(this, list);
		listView.setAdapter(adapter);
	}

	public class ListAdapter extends BaseAdapter implements Filterable {
		private final MyContactFilter mFilter;
		private LayoutInflater inflater;
		private List<Contact> list;

		public ListAdapter(Context context, List<Contact> list) {
			mFilter = new MyContactFilter();
			this.inflater = LayoutInflater.from(context);
			this.list = list;
			alphaIndexer = new HashMap<String, Integer>();
			sections = new String[list.size()];

			for (int i = 0; i < list.size(); i++) {
				// 当前汉语拼音首字母
				String currentStr = getAlpha(list.get(i).getSortKey());
				// 上一个汉语拼音首字母,如果不存在为“ ”
				String previewStr = (i - 1) >= 0 ? getAlpha(list.get(i - 1)
						.getSortKey()) : " ";
				if (!previewStr.equals(currentStr)) {
					String name = getAlpha(list.get(i).getSortKey());
					alphaIndexer.put(name, i);
					sections[i] = name;
				}
			}
		}

		@Override
		public int getCount() {
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			return list.get(position);
		}

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

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			if (convertView == null) {
				convertView = inflater.inflate(R.layout.list_item, null);
				holder = new ViewHolder();
				holder.avatar = (ImageView) convertView
						.findViewById(R.id.imageHeader);
				holder.alpha = (TextView) convertView.findViewById(R.id.alpha);
				holder.name = (TextView) convertView.findViewById(R.id.title);
				holder.number = (TextView) convertView
						.findViewById(R.id.content);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			holder.name.setText(list.get(position).getName());
			holder.number.setText(list.get(position).getMobile());

			return convertView;
		}

		private class ViewHolder {
			ImageView avatar;
			TextView alpha;
			TextView name;
			TextView number;
		}

		/**
		 * A Filter which select Contact to display by searching in ther Jid.
		 */
		private class MyContactFilter extends Filter {

			/**
			 * Create a ContactFilter.
			 */
			public MyContactFilter() {
			}

			@Override
			protected Filter.FilterResults performFiltering(
					CharSequence constraint) {
				Log.d(TAG, "performFiltering");
				List<Contact> result = new LinkedList<Contact>();
				String condition = (String) constraint;
				condition = condition.trim();
				// List<Contact> target = mContactOnGroup.get(mSelectedGroup);
				// L.d("target="+target);
				if (queryFlag) {
					queryList = list;
					queryFlag = false;
				}

				try {
					for (Contact obj : queryList) {
						// L.d(lc.displayName + lc.phone + lc.id);
						if ("".equals(condition)) {
							result.add(obj);
						} else if (obj.getSortKey() != null
								&& obj.getSortKey().contains(condition)
								|| (obj.getMobile() != null && obj.getMobile()
										.contains(condition))) {
							result.add(obj);
						}
					}
				} catch (Exception e) {
					Log.d(TAG, e.toString());
				}
				Filter.FilterResults fr = new Filter.FilterResults();
				fr.values = result;
				fr.count = result.size();
				return fr;
			}

			@Override
			protected void publishResults(CharSequence constraint,
					Filter.FilterResults results) {
				Log.d(TAG, "publishResults");
				List<Contact> contacts = (List<Contact>) results.values;
				setAdapter(contacts);
			}
		}

		@Override
		public Filter getFilter() {
			// TODO Auto-generated method stub
			return mFilter;
		}

	}

	/**
	 * 实现通讯录字母索引
	 */

	// 查询联系人
	private class MyAsyncQueryHandler extends AsyncQueryHandler {

		public MyAsyncQueryHandler(ContentResolver cr) {
			super(cr);

		}

		@Override
		protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
			if (cursor != null && cursor.getCount() > 0) {
				mListLocalContact = new ArrayList<Contact>();
				cursor.moveToFirst();

				for (int i = 0; i < cursor.getCount(); i++) {
					Contact cv = new Contact();
					cursor.moveToPosition(i);
					String name = cursor.getString(1);
					String number = cursor.getString(2);
					String sortKey = cursor.getString(3);
					if (number.startsWith("+86")) {
						cv.setName(name);
						cv.setMobile(number.substring(3));// 去掉+86
						cv.setSortKey(sortKey);
					} else {
						cv.setName(name);
						cv.setMobile(number);
						cv.setSortKey(sortKey);
					}
					mListLocalContact.add(cv);
				}
				if (mListLocalContact.size() > 0) {
					setAdapter(mListLocalContact);
				}
			}
		}

	}

	// 初始化汉语拼音首字母弹出提示框
	private void initOverlay() {
		LayoutInflater inflater = LayoutInflater.from(this);
		overlay = (TextView) inflater.inflate(R.layout.overlay, null);
		overlay.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 = (WindowManager) this
				.getSystemService(Context.WINDOW_SERVICE);
		windowManager.addView(overlay, lp);
	}

	private class LetterListViewListener implements
			OnTouchingLetterChangedListener {

		@Override
		public void onTouchingLetterChanged(final String s) {
			if (overlayFlag) {
				initOverlay();
				overlayFlag = false;
			}
			if (alphaIndexer.get(s) != null) {
				int position = alphaIndexer.get(s);
				listView.setSelection(position);
				overlay.setText(sections[position]);
				overlay.setVisibility(View.VISIBLE);
				handler.removeCallbacks(overlayThread);
				// 延迟一秒后执行,让overlay为不可见
				handler.postDelayed(overlayThread, 1500);
			}
		}

	}

	// 设置overlay不可见
	private class OverlayThread implements Runnable {

		@Override
		public void run() {
			overlay.setVisibility(View.GONE);
		}

	}

	// 获得汉语拼音首字母
	private String getAlpha(String str) {
		if (str == null) {
			return "#";
		}

		if (str.trim().length() == 0) {
			return "#";
		}

		char c = str.trim().substring(0, 1).charAt(0);
		// 正则表达式,判断首字母是否是英文字母
		Pattern pattern = Pattern.compile("^[A-Za-z]+$");
		if (pattern.matcher(c + "").matches()) {
			return (c + "").toUpperCase();
		} else {
			return "#";
		}
	}

	class MyFindContactTextWatcher implements TextWatcher {

		@Override
		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {
			Log.e(TAG, "beforeTextChanged...");
		}

		@Override
		public void onTextChanged(CharSequence s, int start, int before,
				int count) {
			Log.e(TAG, "onTextChanged...");
		}

		@Override
		public void afterTextChanged(Editable s) {
			Log.e(TAG, "onTextChanged...");
			adapter.getFilter().filter(queryContent.getText());
		}

	}

	class MyOnClickListener implements OnClickListener {
		@Override
		public void onClick(View v) {
			// 查询过滤
			adapter.getFilter().filter(queryContent.getText());

		}
	}

	// listView item点击事件
	class MyListItemClickListener implements OnItemClickListener {

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			Toast.makeText(PzFilterActivity.this,
					String.valueOf(position) + " id=" + id, 0).show();

		}

	}

	// listView item长按事件
	class MyOnItemLongClickListener implements OnItemLongClickListener {

		@Override
		public boolean onItemLongClick(AdapterView<?> parent, View view,
				int position, long id) {
			Toast.makeText(PzFilterActivity.this, id + " 长按 " + position, 0)
					.show();
			return false;
		}
	}
}

实体类Contact.java

package com.pz.filter;

public class Contact {
	private int headerImage;
	private String name;
	private String mobile;
	private String sortKey;

	public int getHeaderImage() {
		return headerImage;
	}

	public void setHeaderImage(int headerImage) {
		this.headerImage = headerImage;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getMobile() {
		return mobile;
	}

	public void setMobile(String mobile) {
		this.mobile = mobile;
	}

	public String getSortKey() {
		return sortKey;
	}

	public void setSortKey(String sortKey) {
		this.sortKey = sortKey;
	}

}

布局文件

main.xml

<?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:orientation="vertical"
    android:background="@drawable/branana" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/queryBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="查询" />
        <EditText
            android:id="@+id/queryContent"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/queryBtn"
            android:hint="香蕉你个巴拉..." />

    </RelativeLayout>
    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="horizontal"
        android:padding="2px" >

        <ListView
            android:id="@+id/listview"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="@null"
            android:cacheColorHint="#00000000"
            android:divider="#d9d9d9"
            android:dividerHeight="1dip"
            android:textFilterEnabled="true"
            android:transcriptMode="disabled" />

        <com.pz.filter.view.MyLetterListView
            android:id="@+id/MyLetterListView01"
            android:layout_width="30dip"
            android:layout_height="fill_parent"
            android:layout_alignParentRight="true"
            android:background="#40000000" />
    </RelativeLayout>

</LinearLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="50dp"
    android:orientation="vertical"
    android:background="@null"
    android:layout_gravity="center_vertical" >
    <TextView
		android:id="@+id/alpha"
		android:layout_width="fill_parent"
  		android:layout_height="wrap_content"
  		android:paddingLeft="13dip"
  		android:background="#333333"
		android:textColor="#99CCFF"
		android:textAppearance="?android:textAppearanceMedium"
		android:visibility="gone" />
    <ImageView 
        android:id="@+id/imageHeader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/voicecall"
        />
    <TextView 
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="linxi"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:textColor="#000000"
        android:layout_marginTop="3dp"
        />
    <TextView 
        android:id="@+id/content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="神马都是浮云"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:textColor="#000000"
        android:layout_marginBottom="5dp"
        />

</RelativeLayout>

提示字母View样式

overlay.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView
  	xmlns:android="http://schemas.android.com/apk/res/android"
  	android:textSize="70sp"
    android:textColor="#33cc00"
    android:background="@drawable/qletter_bg"
    android:minWidth="80dip"  
    android:maxWidth="80dip"
    android:padding="5dip"
    android:gravity="center" 
/>
最后别忘添加权限:因为我偷个懒,直接使用的是手机联系人数据,所以要在 AndroidManifest.xml加上读取联系人的权限:

<uses-permission android:name="android.permission.READ_CONTACTS" />


最后提示如果是自己封装数据,想要获取汉字字母首字母,可以使用网上提供的一个pinyin4j.jar开源jar去实现,这是个人在实现项目时自己想出的一招,如果哪位大侠有高招,还请多多赐教,先歇歇啦。

代码中有不足之处,还请大家多多指出,多谢拍砖!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值