聯絡人列表字母排序索引(三)
也是忙忙碌碌好幾天,今天又有時間了,繼續這個文章的編寫。
閱讀這篇文章之前,請先閱讀
今天是這篇文章的最後一部分,主要內容包括以下幾點:
1.將中文名字轉化成拼音,並提取首字母,進行排序。
2.實現分組列表Adapter模板。
3.將列表與索引結合在一起。
pinyin4j是一個將中文轉化成拼音的高效工具,我的原始碼中帶了這個依賴包。通過這個工具,可以先獲取一箇中文的拼音。
public static String getLetter(String name) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < name.length(); i++) { char c = name.charAt(i); String[] str = PinyinHelper.toHanyuPinyinStringArray(c); if (str != null && str.length >= 1) { sb.append(str[0].charAt(0)); } else { sb.append(c); } } return sb.toString(); }
PinyinHelper.tohanyuPinyinStringArray(),將每個char轉化成拼音,我這裡只提取每個漢字的第一個拼音字母,最後返回的結果是字串的拼音簡寫。比如:張三丰---zsf
上面的步驟,已經可以將中文轉化成拼音簡寫了,下面,要做的是什麼呢?
下面的思路是這樣的:
1.先對列表資料按字母順序排序。
2.adapter的每一個itemView都是帶字母分組頭和內容的。只是,只有在一組中文開頭的首個位置才顯示。也就是說,張三丰,張君寶等,排在第一個的顯示頭部,也就是z,其他的隱藏頭部。所以這個位置要計算出來。
3.因為每一個item包含了頭部,所以,點選事件需要在真實內容區域,不在頭部。因此,ListView的點選事件需要禁用,把事件寫在adapter的內容控制元件上。
1.1.先對字母排序,排序需要知道排序的內容,先定義一個介面:
package com.mjc.contactlistdemo.sort_by_letter;
/**
* Created by mjc on 2016/5/24.
*/
public interface ISort {
String getSortName();
}
之後,我們需要使用的資料,只要繼承他,就可以使用我的帶字母索引列表。
1.2.自定義排序方法:
排序的方法,需要我們藉助Collections的sorts方法來排序:
/** * 按照字母排序 * * @param list * @return */ public static <T extends ISort> void sortByLetter(ArrayList<T> list) { Collections.sort(list, new Comparator<T>() { @Override public int compare(T lhs, T rhs) { String l = getLetter(lhs.getSortName()); String r = getLetter(rhs.getSortName()); int minLength = Math.min(l.length(), r.length()); int result = 0; for (int i = 0; i < minLength; i++) { if (l.charAt(i) < r.charAt(i)) { result = -1; break; } else if (l.charAt(i) > r.charAt(i)) { result = 1; break; } else { result = 0; continue; } } if (result == 0) { return l.length() > r.length() ? 1 : -1; } return result; } }); }
用的是泛型,只要實現了Isort的實體類,都可以用它來排序。排序的過程,主要是compare方法,這個方法的返回值,決定了你的排序。每次比較兩個數值,結果由返回值決定。具體的說,就是lhs要排在rhs左邊,返回值就要小於0,;反之,一樣。
2.1.Adapter的實現。
我將計算都提取到了一個BaseSortByLetterAdapter裡面,但是在子Adapter裡面,需要呼叫BaseSortByLetterAdapter的方法,得到第一個分組的位置。
package com.mjc.contactlistdemo.sort_by_letter;
import android.widget.BaseAdapter;
import android.widget.SectionIndexer;
import java.util.ArrayList;
/**
* Created by mjc on 2016/5/24.
*/
public abstract class BaseSortByLetterAdapter<T> extends BaseAdapter implements SectionIndexer {
protected String[] sections;
protected ArrayList<T> datas;
public BaseSortByLetterAdapter(ArrayList<T> datas) {
sections = new 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","#"};
this.datas = datas;
}
@Override
public String[] getSections() {
return sections;
}
//需要進行排序的字串
protected abstract String getSortString(T bean);
//通過section位置,獲取首個position位置
@Override
public int getPositionForSection(int sectionIndex) {
String section = sections[sectionIndex];
//todo ListView的資料要按照字母順序排列
for (int i = 0; i < getCount(); i++) {
T bean = datas.get(i);
String headerLetter = SortUtil.getLetter(getSortString(bean));
if (String.valueOf(headerLetter.charAt(0)).equalsIgnoreCase(section)) {
return i;
} else if (sectionIndex == 0) {
return 0;
}
}
return -1;
}
//通過位置獲取sectionIndex位置
@Override
public int getSectionForPosition(int position) {
T bean = datas.get(position);
String name = getSortString(bean);
String letter = SortUtil.getLetter(name);
String header = String.valueOf(letter.charAt(0));
for (int i = 0; i < sections.length; i++) {
if (sections[i].equalsIgnoreCase(header)) {
return i;
}
}
return 0;
}
public int getSectionIndex(String section) {
for (int i = 0; i < sections.length; i++) {
if (section.equalsIgnoreCase(sections[i])) {
return i;
}
}
return 0;
}
}
implements SectionIndexer,這個東西不是重點,他的作用是,當你開啟ListView的快速滑動後,拖動滑動條是可以顯示當前所處的資料的字母。只不過我這裡實現方式,和系統的原理差不多,因此也是實現了這個介面,之後用到我們的IndexView上就好。
這裡面重要的一點是:我們需要知道第一個字母出現的位置,以便於我們現實這個位置的title字母,其他位置隱藏。這樣我們的分組效果就能實現了。 為了獲取這個位置,我們的邏輯是這樣的:通過位置獲取當前位置的字母,再通過這個字母獲取這個字母在列表中的第一個位置,如果第一個位置和當前位置相同則表示是第一個位置。上面的主要兩個方法就是為這個服務的。
通過位置獲取對應的字母字母的位置,原理很簡單,先獲取當前資料的排序字母,然後和字母列表比較,得到字母的位置。
@Override
public int getSectionForPosition(int position) {
T bean = datas.get(position);
String name = getSortString(bean);
String letter = SortUtil.getLetter(name);
String header = String.valueOf(letter.charAt(0));
for (int i = 0; i < sections.length; i++) {
if (sections[i].equalsIgnoreCase(header)) {
return i;
}
}
return 0;
}
再通過字母的位置,獲取列表中第一個資料的位置,之後在getView中將這個位置和當前位置做比較,如果相等,就顯示title,不相等就隱藏。
//通過section位置,獲取首個position位置
@Override
public int getPositionForSection(int sectionIndex) {
String section = sections[sectionIndex];
//todo ListView的資料要按照字母順序排列
for (int i = 0; i < getCount(); i++) {
T bean = datas.get(i);
String headerLetter = SortUtil.getLetter(getSortString(bean));
if (String.valueOf(headerLetter.charAt(0)).equalsIgnoreCase(section)) {
return i;
} else if (sectionIndex == 0) {
return 0;
}
}
return -1;
}
到這裡,基本是結束了,接下來是使用方法:
1.定義一個實體類,實現Isort介面。
2.定義一個Adpater,繼承BaseSortByLetterAdapter
3.Activity中,setAdapter之前,先使用SortUtil對資料進行排序。
ContactEntity.class
package com.mjc.contactlistdemo.core.contact.entity;
import com.mjc.contactlistdemo.sort_by_letter.ISort;
/**
* Created by mjc on 2016/5/12.
*/
public class ContactEntity implements ISort {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getSortName() {
return name;
}
}
ContactAdapter.class
package com.mjc.contactlistdemo.core.contact;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.mjc.contactlistdemo.R;
import com.mjc.contactlistdemo.core.contact.entity.ContactEntity;
import com.mjc.contactlistdemo.sort_by_letter.BaseSortByLetterAdapter;
import java.util.ArrayList;
/**
* Created by mjc on 2016/5/24.
*/
public class ContactAdapter extends BaseSortByLetterAdapter<ContactEntity> {
public ContactAdapter(ArrayList<ContactEntity> datas) {
super(datas);
}
@Override
protected String getSortString(ContactEntity bean) {
return bean.getSortName();
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder mHolder;
if (convertView == null) {
mHolder = new Holder();
convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_contact, null);
mHolder.mNameTv = (TextView) convertView.findViewById(R.id.tv_name);
mHolder.mIndexTv = (TextView) convertView.findViewById(R.id.tv_index);
convertView.setTag(mHolder);
} else {
mHolder = (Holder) convertView.getTag();
}
//強轉需要注意原來的型別
ContactEntity bean = datas.get(position);
//獲取對應字母的位置
int index = getSectionForPosition(position);
//比較列表中第一個字母的位置和這個位置是否相等
if (getPositionForSection(index) == position) {
mHolder.mIndexTv.setVisibility(View.VISIBLE);
mHolder.mIndexTv.setText(sections[index]);
} else {
mHolder.mIndexTv.setVisibility(View.GONE);
}
mHolder.mNameTv.setText(bean.getName());
return convertView;
}
class Holder {
public TextView mNameTv;
public TextView mIndexTv;
}
}
item_contact.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_index"
style="@style/KeyStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#f4f6f3"
android:paddingTop="12dp"
android:paddingBottom="4dp"
android:textSize="14sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fdfdfd"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:paddingBottom="5dp"
android:paddingLeft="10dp"
android:paddingTop="5dp"
android:src="@mipmap/ic_launcher"
android:visibility="gone" />
<TextView
android:id="@+id/tv_name"
style="@style/InputStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
MainActivity.class
package com.mjc.contactlistdemo.core.contact;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ListView;
import com.mjc.contactlistdemo.R;
import com.mjc.contactlistdemo.core.contact.entity.ContactEntity;
import com.mjc.contactlistdemo.sort_by_letter.IndexView;
import com.mjc.contactlistdemo.sort_by_letter.LetterWindow;
import com.mjc.contactlistdemo.sort_by_letter.SortUtil;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity implements IndexView.OnCharTouchEvent {
private LetterWindow mLetterWindow;
private ContactAdapter mContactAdapter;
private IndexView mIndexView;
private ListView mList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mList = (ListView) findViewById(R.id.list);
mIndexView = (IndexView) findViewById(R.id.civ);
mIndexView.setOnLetterTouchedListener(this);
mLetterWindow = new LetterWindow(this);
ArrayList<ContactEntity> list = new ArrayList<>();
ContactEntity bean1 = new ContactEntity();
bean1.setName("單熊信");
ContactEntity bean2 = new ContactEntity();
bean2.setName("謝天華");
ContactEntity bean3 = new ContactEntity();
bean3.setName("李自成");
ContactEntity bean4 = new ContactEntity();
bean4.setName("段天涯");
ContactEntity bean5 = new ContactEntity();
bean5.setName("張無忌");
ContactEntity bean6 = new ContactEntity();
bean6.setName("小紅");
ContactEntity bean7 = new ContactEntity();
bean7.setName("李尋歡");
ContactEntity bean8 = new ContactEntity();
bean8.setName("王小亞");
ContactEntity bean9 = new ContactEntity();
bean9.setName("夏冬青");
ContactEntity bean10 = new ContactEntity();
bean10.setName("上官錦");
ContactEntity bean11 = new ContactEntity();
bean11.setName("炎亞綸");
ContactEntity bean12 = new ContactEntity();
bean12.setName("劉德華");
ContactEntity bean13 = new ContactEntity();
bean13.setName("陳浩民");
ContactEntity bean14 = new ContactEntity();
bean14.setName("馬雲");
ContactEntity bean15 = new ContactEntity();
bean15.setName("雷軍");
ContactEntity bean16 = new ContactEntity();
bean16.setName("周巨集偉");
ContactEntity bean17 = new ContactEntity();
bean17.setName("李易峰");
ContactEntity bean18 = new ContactEntity();
bean18.setName("鹿晗");
ContactEntity bean19 = new ContactEntity();
bean19.setName("鄧超");
ContactEntity bean20 = new ContactEntity();
bean20.setName("李晨");
ContactEntity bean21 = new ContactEntity();
bean21.setName("張翰");
ContactEntity bean22 = new ContactEntity();
bean22.setName("鄧麗君");
ContactEntity bean23 = new ContactEntity();
bean23.setName("曾志偉");
ContactEntity bean24 = new ContactEntity();
bean24.setName("阿甘");
ContactEntity bean25 = new ContactEntity();
bean25.setName("爸比");
ContactEntity bean26 = new ContactEntity();
bean26.setName("東方彧卿");
ContactEntity bean27 = new ContactEntity();
bean27.setName("方世玉");
ContactEntity bean28 = new ContactEntity();
bean28.setName("高芳");
ContactEntity bean29 = new ContactEntity();
bean29.setName("海大富");
ContactEntity bean30 = new ContactEntity();
bean30.setName("江離");
ContactEntity bean31 = new ContactEntity();
bean31.setName("康輝");
ContactEntity bean32 = new ContactEntity();
bean32.setName("牛郎");
ContactEntity bean33 = new ContactEntity();
bean33.setName("謝天華");
ContactEntity bean34 = new ContactEntity();
bean34.setName("單雄心");
ContactEntity bean35 = new ContactEntity();
bean35.setName("賽華佗");
list.add(bean1);
list.add(bean2);
list.add(bean3);
list.add(bean4);
list.add(bean5);
list.add(bean6);
list.add(bean7);
list.add(bean8);
list.add(bean9);
list.add(bean10);
list.add(bean11);
list.add(bean12);
list.add(bean13);
list.add(bean14);
list.add(bean15);
list.add(bean16);
list.add(bean17);
list.add(bean18);
list.add(bean19);
list.add(bean20);
list.add(bean21);
list.add(bean22);
list.add(bean23);
list.add(bean24);
list.add(bean25);
list.add(bean26);
list.add(bean27);
list.add(bean28);
list.add(bean29);
list.add(bean30);
list.add(bean31);
list.add(bean32);
list.add(bean33);
list.add(bean34);
list.add(bean35);
SortUtil.sortByLetter(list);
mContactAdapter = new ContactAdapter(list);
mList.setAdapter(mContactAdapter);
}
@Override
public void onTouch(String s) {
mLetterWindow.show(s);
int index = mContactAdapter.getSectionIndex(s);
int position = mContactAdapter.getPositionForSection(index);
if (position != -1)
mList.setSelection(position);
}
@Override
public void onLetterChanged(String preLetter, String letter) {
mLetterWindow.update(letter);
int index = mContactAdapter.getSectionIndex(letter);
int position = mContactAdapter.getPositionForSection(index);
if (position != -1)
mList.setSelection(position);
}
@Override
public void onRelease() {
mLetterWindow.hide();
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<ListView
android:id="@+id/list"
style="@style/CustomList"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.mjc.contactlistdemo.sort_by_letter.IndexView
android:id="@+id/civ"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right" />
</FrameLayout>
</LinearLayout>
以上就是使用的過程,還是很簡便的。
到這裡,這個字母索引排序就算是寫完了,謝謝!