android字母索引流程:
界面步骤:
1、初始化右侧字母的高度以及大小
2、回执索引列表,并为列表当中的字母设置监听事件
业务逻辑步骤:
1、先从服务器读取我的好友列表
2、将好友的名字转换为拼音,并取得首字母,按照字母大小进行排序。装载联系人非字母为首的数组。保存到selector HashMap当中。键为联系人的字母的开头,值为联系人在这个集合里面的下标
3、取得返回数据装载到适配器里面去
1、初始化右侧字母的高度以及大小
2、回执索引列表,并为列表当中的字母设置监听事件
业务逻辑步骤:
1、先从服务器读取我的好友列表
2、将好友的名字转换为拼音,并取得首字母,按照字母大小进行排序。装载联系人非字母为首的数组。保存到selector HashMap当中。键为联系人的字母的开头,值为联系人在这个集合里面的下标
3、取得返回数据装载到适配器里面去
会用到的第三方库:pinyin4j.jar :http://download.csdn.net/detail/q908555281/9296197
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- 这个用来显示联系人的列表 -->
<ListView
android:id="@+id/listview_news_friends"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/comment_background"
android:cacheColorHint="#00000000"
android:divider="@null"
android:fadingEdge="none"
android:scrollbars="none" >
</ListView>
<!-- 这个用来显示右侧字母栏的布局 -->
<LinearLayout
android:id="@+id/lilayout_news_friends"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:background="#d7d7d7"
android:gravity="center"
android:orientation="vertical" >
</LinearLayout>
<!-- 这个用来显示点击字母后,屏幕中间出现的字母提示 -->
<TextView
android:id="@+id/tv_news_friends_letter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@color/white"
android:gravity="center"
android:paddingBottom="@dimen/px_20"
android:paddingLeft="@dimen/px_30"
android:paddingRight="@dimen/px_30"
android:paddingTop="@dimen/px_20"
android:text="A"
android:textColor="@color/common_text_input"
android:textSize="@dimen/text_size_25"
android:visibility="gone" />
</FrameLayout>
主类:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;
import com.lidroid.xutils.ViewUtils;
import com.lidroid.xutils.view.annotation.ViewInject;
import com.slife.gopapa.R;
import com.slife.gopapa.activity.news.ContactsActivity;
import com.slife.gopapa.adapter.FriendsAdapter;
import com.slife.gopapa.application.MyApplication;
import com.slife.gopapa.common.APPConstants;
import com.slife.gopapa.dao.JArrayErrorDao;
import com.slife.gopapa.dao.impl.JArrayErrorDaoImpl;
import com.slife.gopapa.database.DBConstants;
import com.slife.gopapa.http.MyHttpClient;
import com.slife.gopapa.model.ContactsPerson;
import com.slife.gopapa.util.ChineseTransferUtils;
/**
* @ClassName: FriendsFragment
* @Description: 我的好友界面
* 界面步骤:
* 1、初始化右侧字母的高度以及大小
* 2、回执索引列表,并为列表当中的字母设置监听事件
*
* 业务逻辑步骤:
* 1、先从服务器读取我的好友列表
* 2、将好友的名字转换为拼音,并取得首字母,按照字母大小进行排序。装载联系人非字母为首的数组。保存到selector HashMap当中。键为联系人的字母的开头,值为联系人在这个集合里面的下标
*
* 3、取得返回数据装载到适配器里面去
* @author 菲尔普斯
* @date 2015-3-26 下午5:12:37
*
*/
public class FriendsFragment extends Fragment {
@ViewInject(R.id.listview_news_friends)
private ListView listView; // 联系人列表
@ViewInject(R.id.tv_news_friends_letter)
private TextView txCenter; // 显示在中间的字母
@ViewInject(R.id.lilayout_news_friends)
private LinearLayout layoutIndex;
private HashMap<String, Integer> selector = new HashMap<String, Integer>();// 存放含有索引字母的位置
private static final String[] indexStr = { "☆", "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 List<ContactsPerson> newPersons = new ArrayList<ContactsPerson>();// 对联系人进行转换成拼音
private int height;// 字体高度
private boolean flag = false;// 选中标签
private FriendsAdapter adapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_friends, container,
false);
ViewUtils.inject(this, view);
View headView = inflater.inflate(R.layout.view_friends_headview, null);
listView.addHeaderView(headView);
initOverload();
initListView();
return view;
}
private void initListView() {
adapter = new FriendsAdapter(getActivity(), newPersons);
listView.setAdapter(adapter);
new GetFriendListTask().execute();
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if(position==0){
startActivity(new Intent(getActivity(),ContactsActivity.class));
}
}
});
}
/**
* @Title: initOverload
* @Description: 初始化右侧字母栏高度
* @param
* @return void
* @throws
*/
private void initOverload() {
// 这是获取屏幕宽高的监听器
ViewTreeObserver observer = layoutIndex.getViewTreeObserver();
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
if (!flag) {
// 获取每个字母的高度
height = layoutIndex.getMeasuredHeight() / indexStr.length;
getIndexView();
flag = true;
}
return true;
}
});
}
/**
* @Title: getIndexView
* @Description: 绘制索引列表(字母列表的监听事件)
* @param
* @return void
* @throws
*/
public void getIndexView() {
LinearLayout.LayoutParams params = new LayoutParams(
LayoutParams.WRAP_CONTENT, height);
for (int i = 0; i < indexStr.length; i++) {
final TextView tv = new TextView(this.getActivity());// 右侧字母索引
tv.setLayoutParams(params);
tv.setText(indexStr[i]);// 右侧字母
tv.setPadding(10, 0, 10, 0);
tv.setTextSize(12);
tv.setTextColor(Color.parseColor("#3E75A9"));
layoutIndex.addView(tv);// 设置右侧索引布局的触摸监听器
layoutIndex.setOnTouchListener(new OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
float y = event.getY();
int index = (int) (y / height);
if (index > -1 && index < indexStr.length) {// 防止越界
String key = indexStr[index];
if (selector.containsKey(key)) {
int pos = selector.get(key);
// 将ListView的item移动到点击相应字母
if (listView.getHeaderViewsCount() > 0) {// 防止ListView有标题栏,本例中没有。
listView.setSelectionFromTop(
pos + listView.getHeaderViewsCount(), 0);
} else {
listView.setSelectionFromTop(pos, 0);// 滑动到第一项
}
txCenter.setVisibility(View.VISIBLE);
txCenter.setText(indexStr[index]);
} else {
txCenter.setVisibility(View.VISIBLE);
txCenter.setText(indexStr[index]);
}
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
layoutIndex.setBackgroundColor(Color
.parseColor("#606060"));
txCenter.setVisibility(View.VISIBLE);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
layoutIndex.setBackgroundColor(Color
.parseColor("#00ffffff"));
txCenter.setVisibility(View.GONE);
break;
}
return true;
}
});
}
}
/**
* @ClassName: GetFriendListTask
* @Description: 取得我的好友列表
* @author 菲尔普斯
* @date 2015-3-26 下午5:13:45
*
*/
class GetFriendListTask extends AsyncTask<Void, Void, String[]> {
@Override
protected String[] doInBackground(Void... params) {
return MyHttpClient.postDataToService(getActivity(),
APPConstants.URL_HOSTNAME
+ APPConstants.URL_FRIENDS_LISTSAPP2,
MyApplication.tokenApp2, new String[] { "user_account" },
new String[] { MyApplication.preferences.getString(DBConstants.USER_ACCOUNT, "") }, null,
null);
}
@Override
protected void onPostExecute(String[] result) {
super.onPostExecute(result);
JArrayErrorDaoImpl.resolveJson(getActivity(), result,
new JArrayErrorDao() {
@Override
public void disposeJsonArray(JSONArray array) {
if (array != null && array.length() > 0) {
for (int i = 0; i < array.length(); i++) {
try {
JSONObject obj = array.getJSONObject(i);
ContactsPerson info = new ContactsPerson();
info.setUser_account(obj
.optString("friend_user_account"));
info.setExtend_user_account(obj
.optString("friend_extend_user_account"));
info.setUser_nickname(obj
.optString("user_nickname"));
info.setUser_logo(obj
.getString("user_logo_200"));
info.setName(obj
.optString("user_nickname"));
newPersons.add(info);
} catch (JSONException e) {
e.printStackTrace();
}
}
layoutIndex.setBackgroundColor(Color.parseColor("#00ffffff"));// 设置背景颜色
txCenter.setVisibility(View.GONE);
initPinyin();
}
}
@Override
public void disponseJsonArrayFinish() {
// TODO Auto-generated method stub
}
});
}
}
/**
* @Title: getPinyin
* @Description: 获取每个人的拼音的首字母,并setPinyinName为这个首字母。然后将集合进行排序。再将集合里面的每个首字母和Position的位置存放到selector对象当中
* @param
* @return void
* @throws
*/
@SuppressLint("DefaultLocale")
private void initPinyin(){
for(int i=0;i<newPersons.size();i++){
String name=newPersons.get(i).getUser_nickname();
if(name!=null&&!"".equals(name)){
String pinyin=ChineseTransferUtils.getPingYin(name);
newPersons.get(i).setPinyinName((pinyin.substring(0, 1)).toUpperCase());
}
}
Collections.sort(newPersons); //对联系人进行排序从A-Z(根据pinyinName)
for(int j=0;j<indexStr.length;j++){
for(int i=0;i<newPersons.size();i++){
if(newPersons.get(i).getPinyinName().equals(indexStr[j])){
if(!selector.containsKey(indexStr[j])){
selector.put(indexStr[j], i);
}
}else{
if(!selector.containsKey("#")){
selector.put("#", i);
}
}
}
}
adapter.notifyDataSetChanged();
}
}
字母处理工具类:
import java.util.Arrays;
import java.util.List;
import java.util.TreeSet;
import com.slife.gopapa.model.ContactsPerson;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
/****
* @ClassName: ChineseTransferUtils
* @Description: 汉字与拼音以及首字母转换的助手类(pingyin4j的处理)
* @author 菲尔普斯
* @date 2015-2-2 上午9:59:21
*
*/
public class ChineseTransferUtils {
/**
* @Title: getPingYin
* @Description: 得到 汉字的全部拼音
* @param @param src 要转换的对象
* @param @return
* @return String
* @throws
*/
public static String getPingYin(String src) {
char[] stringCharArray = null;
stringCharArray = src.toCharArray();
String[] stringArray = new String[stringCharArray.length];
HanyuPinyinOutputFormat outputFormat = new HanyuPinyinOutputFormat();
// 设置输出格式
outputFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
outputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
outputFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
String preString = "";
int t0 = stringCharArray.length;
try {
for (int i = 0; i < t0; i++) {
// 判断是否为汉字字符
if (java.lang.Character.toString(stringCharArray[i]).matches(
"[\\u4E00-\\u9FA5]+")) {
stringArray = PinyinHelper.toHanyuPinyinStringArray(
stringCharArray[i], outputFormat);
preString += stringArray[0];
} else {
preString += java.lang.Character
.toString(stringCharArray[i]);
}
}
return preString;
} catch (BadHanyuPinyinOutputFormatCombination e1) {
e1.printStackTrace();
}
return preString;
}
/**
* @Title: getHeadChar
* @Description: 得到首字母
* @param @param str
* @param @return
* @return String
* @throws
*/
public static String getHeadChar(String str) {
String convert = "";
char word = str.charAt(0);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
if (pinyinArray != null) {
convert += pinyinArray[0].charAt(0);
} else {
convert += word;
}
return convert.toUpperCase();
}
/**
* @Title: getPinYinHeadChar
* @Description: 得到中文首字母缩写
* @param @param str
* @param @return
* @return String
* @throws
*/
public static String getPinYinHeadChar(String str) {
String convert = "";
for (int j = 0; j < str.length(); j++) {
char word = str.charAt(j);
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
if (pinyinArray != null) {
convert += pinyinArray[0].charAt(0);
} else {
convert += word;
}
}
return convert.toUpperCase();
}
/**
* @Title: sortIndex
* @Description: 字母排序。获取排序后的新数据
* @param @param persons
* @param @return
* @return String[]
* @throws
*/
public static String[] sortIndex(List<ContactsPerson> contacts) {
TreeSet<String> set = new TreeSet<String>();
String a = null;
// 获取初始化数据源中的首字母,添加到set中
for (ContactsPerson person : contacts) {
String pre = ChineseTransferUtils.getPinYinHeadChar(person.getName()).substring(0, 1);
if (65 <= pre.charAt(0) && pre.charAt(0) <= 90 || 97 <= pre.charAt(0) && pre.charAt(0) <= 122) {
set.add(pre);
} else {
set.add("!");
}
}
// 新数组的长度为原数据加上set的大小(set内部已经按字母大小排序,将set里的数据装载到数组中以便往后调用系统拷贝方法)
String[] names = new String[contacts.size() + set.size()];
int i = 0;
for (String string : set) {
names[i] = string;
i++;
}
String[] pinYinNames = new String[contacts.size()];
for (int j = 0; j < contacts.size(); j++) {
contacts.get(j).setPinyinName(a = ChineseTransferUtils.getPingYin(contacts.get(j).getName().toString()));
pinYinNames[j] = a + "&^-@";
}
// 将原数据拷贝到新数据中(将pinYinNames数组中的元素从0下标开始复制元素到names数组)
// src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置;
// length:复制的长度。 注意:src and dest都必须是同类型或者可以进行转换类型的数组.
System.arraycopy(pinYinNames, 0, names, set.size(), pinYinNames.length);
// 复制后自动按照首字母排序
Arrays.sort(names, String.CASE_INSENSITIVE_ORDER);// 这个方法得到的数组不是以A为开头的,所以下面的方法就是重新排布用户名的顺序
/**************** 重新排布用户名的顺序开始 ************************/
String[] newNames = new String[names.length + 1];// 装载以A为首的数组
String[] postNames = new String[names.length];// 装载非字母为首的数组
int k = 0;
int postCount = 0;
int temp = 0;
for (String pre : names) {
if (65 <= pre.charAt(0) && pre.charAt(0) <= 90 || 97 <= pre.charAt(0) && pre.charAt(0) <= 122) {
// 字母开头的数组
newNames[k] = names[temp];
k++;
temp++;
} else {
// 非字母开头的数组
postNames[postCount] = names[postCount];
temp = ++postCount;
}
}
// 将非字母开头的数组加到字母开头数组的后面
for (int j = 0; j < postCount; j++, k++) {
newNames[k] = postNames[j];
}
temp = 0;
// 防止数组中有null
for (String pew : newNames) {
if (pew != null)
postNames[temp++] = pew;
}
/**************** 重新排布用户名的顺序结束 ************************/
return postNames;
}
}
最后的实体类:因为实体类需要进行排序,所以重写compareTo方法
import java.io.Serializable;
/**
* @ClassName: ContactsPerson
* @Description: 我的好友实体类和通讯录实体类公用 通讯录联系人的实体类 ,以及好友请求列表的实体类
*
* status 联系人状态 -2 : 不是手机号 -1 : 是手机但是没有注册啪啪,可邀请 0 :
* 是手机且已经注册啪啪,不可添加为好友 1 : 是手机且已经注册啪啪,可添加为好友 2 : 是手机且已经注册啪啪,已经是好友
* @author 菲尔普斯
* @date 2015-1-4 下午2:15:48
*
*/
public class ContactsPerson implements Serializable,Comparable<ContactsPerson> {
/**
* @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么)
*/
private static final long serialVersionUID = -8839670785761661380L;
public String name;// 中文名
public String pinyinName;// 拼音的名字
public String phone; // 电话号码
public String status;// 是不是好友(状态,默认-1,代表是还未处理)
public String user_account; // 啪啪号
public String extend_user_account; // 聊天账号
public String user_nickname; // 用户昵称
public String user_logo; // 用户头像
public ContactsPerson() {
super();
}
public ContactsPerson(String name) {
super();
this.name = name;
}
public ContactsPerson(String name, String pinyinName) {
super();
this.name = name;
this.pinyinName = pinyinName;
}
public ContactsPerson(String name, String pinyinName, String phone) {
super();
this.name = name;
this.pinyinName = pinyinName;
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPinyinName() {
return pinyinName;
}
public void setPinyinName(String pinyinName) {
this.pinyinName = pinyinName;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getUser_account() {
return user_account;
}
public void setUser_account(String user_account) {
this.user_account = user_account;
}
public String getExtend_user_account() {
return extend_user_account;
}
public void setExtend_user_account(String extend_user_account) {
this.extend_user_account = extend_user_account;
}
public String getUser_nickname() {
return user_nickname;
}
public void setUser_nickname(String user_nickname) {
this.user_nickname = user_nickname;
}
public String getUser_logo() {
return user_logo;
}
public void setUser_logo(String user_logo) {
this.user_logo = user_logo;
}
@Override
public int compareTo(ContactsPerson another) {
char a=this.getPinyinName().charAt(0);
char b=another.getPinyinName().charAt(0);
if(Integer.valueOf(a)>Integer.valueOf(b)){
return 1;
}else{
return -1;
}
}
}