用Android实现联系人按字母检索,GitHub - doubijuan/ContactsDome: Android 使用ListView的A-Z字母排序功能实现联系人模块,主要学习了ListVie...

ContactsDome

Android 使用ListView的A-Z字母排序功能实现联系人模块,主要学习了ListView的A-Z字母排序功能以及根据输入框的输入值改变来过滤搜索结果,如果输入框里面的值为空,更新为原来的列表,否则为过滤数据列表,包括汉字转成拼音的功能

先来看一下最终效果图:

1a58e5b70b4e4ffa125e9e2e7335d073.gif

现在我们来看下项目结构图

a4e2f61420d830e6c75f709cf4b08208.png

其实很多都是和上一篇文章一样的,我在这里就不多说啦,不是很明白的地方,可以看一下上一篇文章

我还是按照项目中类的顺序把代码贴出来吧

1.ContactSortModel

package com.adan.contactsdome.view;

public class ContactSortModel {

private String name;//显示的数据

private String sortLetters;//显示数据拼音的首字母

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getSortLetters() {

return sortLetters;

}

public void setSortLetters(String sortLetters) {

this.sortLetters = sortLetters;

}

}

3.PinyinComparator

package com.adan.contactsdome.view;

import java.util.Comparator;

/**

* 用来对ListView中的数据根据A-Z进行排序,前面两个if判断主要是将不是以汉字开头的数据放在后面

*/

public class PinyinComparator implements Comparator {

public int compare(ContactSortModel o1, ContactSortModel o2) {

//这里主要是用来对ListView里面的数据根据ABCDEFG...来排序

if (o1.getSortLetters().equals("@")

|| o2.getSortLetters().equals("#")) {

return -1;

} else if (o1.getSortLetters().equals("#")

|| o2.getSortLetters().equals("@")) {

return 1;

} else {

return o1.getSortLetters().compareTo(o2.getSortLetters());

}

}

}

···

4.PinyinUtils类,就是第一点所讲的PinYin4j.jar用于将汉字转换为拼音啦,这里就不粘贴代码啦,[探索PinYin4j.jar将汉字转换为拼音的基本用法](http://blog.csdn.net/qq_20785431/article/details/50730342)

5.SideBar类就是ListView右侧的字母索引View

```Java

package com.adan.contactsdome.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;

import android.widget.TextView;

import com.adan.contactsdome.R;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

/**

* ListView右侧的字母索引View

*/

public class SideBar extends View {

public static String[] INDEX_STRING = {"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"};

private OnTouchingLetterChangedListener onTouchingLetterChangedListener;

private List letterList;

private int choose = -1;

private Paint paint = new Paint();

private TextView mTextDialog;

public SideBar(Context context) {

this(context, null);

}

public SideBar(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public SideBar(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

init();

}

private void init() {

setBackgroundColor(Color.parseColor("#FFFFFF"));

letterList = Arrays.asList(INDEX_STRING);

}

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

int height = getHeight();// 获取对应高度

int width = getWidth();// 获取对应宽度

int singleHeight = height / letterList.size();// 获取每一个字母的高度

for (int i = 0; i < letterList.size(); i++) {

paint.setColor(Color.parseColor("#606060"));

paint.setTypeface(Typeface.DEFAULT_BOLD);

paint.setAntiAlias(true);

paint.setTextSize(20);

// 选中的状态

if (i == choose) {

paint.setColor(Color.parseColor("#4F41FD"));

paint.setFakeBoldText(true);

}

// x坐标等于中间-字符串宽度的一半.

float xPos = width / 2 - paint.measureText(letterList.get(i)) / 2;

float yPos = singleHeight * i + singleHeight / 2;

canvas.drawText(letterList.get(i), xPos, yPos, paint);

paint.reset();// 重置画笔

}

}

@Override

public boolean dispatchTouchEvent(MotionEvent event) {

final int action = event.getAction();

final float y = event.getY();// 点击y坐标

final int oldChoose = choose;

final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;

final int c = (int) (y / getHeight() * letterList.size());// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

switch (action) {

case MotionEvent.ACTION_UP:

setBackgroundColor(Color.parseColor("#FFFFFF"));

choose = -1;

invalidate();

if (mTextDialog != null) {

mTextDialog.setVisibility(View.GONE);

}

break;

default:

setBackgroundResource(R.drawable.bg_sidebar);

if (oldChoose != c) {

if (c >= 0 && c < letterList.size()) {

if (listener != null) {

listener.onTouchingLetterChanged(letterList.get(c));

}

if (mTextDialog != null) {

mTextDialog.setText(letterList.get(c));

mTextDialog.setVisibility(View.VISIBLE);

}

choose = c;

invalidate();

}

}

break;

}

return true;

}

public void setIndexText(ArrayList indexStrings) {

this.letterList = indexStrings;

invalidate();

}

/**

* 为SideBar设置显示当前按下的字母的TextView

*

* @param mTextDialog

*/

public void setTextView(TextView mTextDialog) {

this.mTextDialog = mTextDialog;

}

/**

* 向外公开的方法

*

* @param onTouchingLetterChangedListener

*/

public void setOnTouchingLetterChangedListener(

OnTouchingLetterChangedListener onTouchingLetterChangedListener) {

this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;

}

/**

* 接口

*/

public interface OnTouchingLetterChangedListener {

void onTouchingLetterChanged(String s);

}

}

6.SortAdapter数据的适配器类,这里我们需要用到的就是SectionIndexer接口,它能够有效地帮助我们对分组进行控制。使用SectionIndexer接口需要实现三个方法:getSectionForPosition(int position),getPositionForSection(int section),getSections(),我们只需要自行实现前面两个方法:

(一)getSectionForPosition(int position)是根据ListView的position来找出当前位置所在的分组

(二)getPositionForSection(int section)就是根据首字母的Char值来获取在该ListView中第一次出现该首字母的位置,也就是当前分组所在的位置

package com.adan.contactsdome;

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.SectionIndexer;

import android.widget.TextView;

import com.adan.contactsdome.view.ContactSortModel;

import java.util.List;

public class SortAdapter extends BaseAdapter implements SectionIndexer {

private List list = null;

private Context mContext;

public SortAdapter(Context mContext, List list) {

this.mContext = mContext;

this.list = list;

}

/**

* 当ListView数据发生变化时,调用此方法来更新ListView

*

* @param list

*/

public void updateListView(List list) {

this.list = list;

notifyDataSetChanged();

}

public int getCount() {

return this.list.size();

}

public Object getItem(int position) {

return list.get(position);

}

public long getItemId(int position) {

return position;

}

public View getView(final int position, View view, ViewGroup arg2) {

ViewHolder viewHolder = null;

final ContactSortModel mContent = list.get(position);

if (view == null) {

viewHolder = new ViewHolder();

view = LayoutInflater.from(mContext).inflate(R.layout.item_contact, null);

viewHolder.tvTitle = (TextView) view.findViewById(R.id.tv_city_name);

view.setTag(viewHolder);

viewHolder.tvLetter = (TextView) view.findViewById(R.id.tv_catagory);

} else {

viewHolder = (ViewHolder) view.getTag();

}

int section = getSectionForPosition(position);

if (position == getPositionForSection(section)) {

viewHolder.tvLetter.setVisibility(View.VISIBLE);

viewHolder.tvLetter.setText(mContent.getSortLetters());

} else {

viewHolder.tvLetter.setVisibility(View.GONE);

}

viewHolder.tvTitle.setText(this.list.get(position).getName());

return view;

}

final static class ViewHolder {

TextView tvLetter;

TextView tvTitle;

}

public int getSectionForPosition(int position) {

return list.get(position).getSortLetters().charAt(0);

}

public int getPositionForSection(int section) {

for (int i = 0; i < getCount(); i++) {

String sortStr = list.get(i).getSortLetters();

char firstChar = sortStr.toUpperCase().charAt(0);

if (firstChar == section) {

return i;

}

}

return -1;

}

@Override

public Object[] getSections() {

return null;

}

}

7.MainActivity 对EditTextWithDel设置addTextChangedListener监听,当输入框内容发生变化根据里面的值过滤ListView,里面的值为空显示原来的列表和给ListView添加表头等

package com.adan.contactsdome;

import android.app.Activity;

import android.os.Bundle;

import android.text.Editable;

import android.text.TextUtils;

import android.text.TextWatcher;

import android.view.View;

import android.widget.AdapterView;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.Toast;

import com.adan.contactsdome.view.ContactSortModel;

import com.adan.contactsdome.view.EditTextWithDel;

import com.adan.contactsdome.view.PinyinComparator;

import com.adan.contactsdome.view.PinyinUtils;

import com.adan.contactsdome.view.SideBar;

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

public class MainActivity extends Activity {

private ListView sortListView;

private SideBar sideBar;

private TextView dialog, mTvTitle;

private SortAdapter adapter;

private EditTextWithDel mEtSearchName;

private List SourceDateList;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initViews();

}

private void initViews() {

mEtSearchName = (EditTextWithDel) findViewById(R.id.et_search);

sideBar = (SideBar) findViewById(R.id.sidrbar);

dialog = (TextView) findViewById(R.id.dialog);

mTvTitle = (TextView) findViewById(R.id.tv_title);

sortListView = (ListView) findViewById(R.id.lv_contact);

initDatas();

initEvents();

setAdapter();

}

private void setAdapter() {

SourceDateList = filledData(getResources().getStringArray(R.array.contacts));

Collections.sort(SourceDateList, new PinyinComparator());

adapter = new SortAdapter(this, SourceDateList);

sortListView.setAdapter(adapter);

}

private void initEvents() {

//设置右侧触摸监听

sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {

@Override

public void onTouchingLetterChanged(String s) {

//该字母首次出现的位置

int position = adapter.getPositionForSection(s.charAt(0));

if (position != -1) {

sortListView.setSelection(position + 1);

}

}

});

//ListView的点击事件

sortListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

@Override

public void onItemClick(AdapterView> parent, View view,

int position, long id) {

mTvTitle.setText(((ContactSortModel) adapter.getItem(position - 1)).getName());

Toast.makeText(getApplication(), ((ContactSortModel) adapter.getItem(position)).getName(), Toast.LENGTH_SHORT).show();

}

});

//根据输入框输入值的改变来过滤搜索

mEtSearchName.addTextChangedListener(new TextWatcher() {

@Override

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override

public void onTextChanged(CharSequence s, int start, int before, int count) {

//当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表

filterData(s.toString());

}

@Override

public void afterTextChanged(Editable s) {

}

});

}

private void initDatas() {

sideBar.setTextView(dialog);

}

/**

* 根据输入框中的值来过滤数据并更新ListView

*

* @param filterStr

*/

private void filterData(String filterStr) {

List mSortList = new ArrayList<>();

if (TextUtils.isEmpty(filterStr)) {

mSortList = SourceDateList;

} else {

mSortList.clear();

for (ContactSortModel sortModel : SourceDateList) {

String name = sortModel.getName();

if (name.toUpperCase().indexOf(filterStr.toString().toUpperCase()) != -1 || PinyinUtils.getPingYin(name).toUpperCase().startsWith(filterStr.toString().toUpperCase())) {

mSortList.add(sortModel);

}

}

}

// 根据a-z进行排序

Collections.sort(mSortList, new PinyinComparator());

adapter.updateListView(mSortList);

}

private List filledData(String[] date) {

List mSortList = new ArrayList<>();

ArrayList indexString = new ArrayList<>();

for (int i = 0; i < date.length; i++) {

ContactSortModel sortModel = new ContactSortModel();

sortModel.setName(date[i]);

String pinyin = PinyinUtils.getPingYin(date[i]);

String sortString = pinyin.substring(0, 1).toUpperCase();

if (sortString.matches("[A-Z]")) {

sortModel.setSortLetters(sortString.toUpperCase());

if (!indexString.contains(sortString)) {

indexString.add(sortString);

}

}

mSortList.add(sortModel);

}

Collections.sort(indexString);

sideBar.setIndexText(indexString);

return mSortList;

}

}

布局文件就不贴出来了,现在看来是不是比上一篇还简单了呢

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值