通讯录(联系人信息)实现
例子:利用PinYin4j框架实现通讯录中信息按照开头首字母分类
1.加入依赖
implementation 'de. hdodenhof: circleimageview: 3.0 .0 '
implementation 'com. github. bumptech. glide: glide: 4.6 .1 '
compile 'com. belerweb: pinyin4j: 2.5 .0 '
< ! -- 允许联网 -- >
< uses - permission android: name= "android.permission.INTERNET" / >
2.创建数据类型
package com. example. app_contract_people. bean ;
public class Person {
private String remark;
private String account;
private String nickName;
private String phoneNumber;
private String area;
private String headerUrl;
private String pinyin;
private boolean is_check;
public boolean getIs_check ( ) {
return is_check;
}
public void setIs_check ( boolean is_check) {
this . is_check = is_check;
}
public String getPinyin ( ) {
return pinyin;
}
public void setPinyin ( String pinyin) {
this . pinyin = pinyin;
}
public void setAccount ( String account) {
this . account = account;
}
public String getAccount ( ) {
return account;
}
public void setArea ( String area) {
this . area = area;
}
public String getArea ( ) {
return area;
}
public void setNickName ( String nickName) {
this . nickName = nickName;
}
public String getNickName ( ) {
return nickName;
}
public String getPhoneNumber ( ) {
return phoneNumber;
}
public void setPhoneNumber ( String phoneNumber) {
this . phoneNumber = phoneNumber;
}
public String getRemark ( ) {
return remark;
}
public void setRemark ( String remark) {
this . remark = remark;
}
public void setHeaderUrl ( String headerUrl) {
this . headerUrl = headerUrl;
}
public String getHeaderUrl ( ) {
return headerUrl;
}
public String getFirstPinyin ( ) {
return pinyin != null ? pinyin. substring ( 0 , 1 ) : "" ;
}
}
3.设置布局
<?xml version="1.0" encoding="utf-8"?>
< androidx.constraintlayout.widget.ConstraintLayout xmlns: android= " http://schemas.android.com/apk/res/android"
xmlns: tools= " http://schemas.android.com/tools"
android: layout_width= " match_parent"
android: layout_height= " match_parent"
android: orientation= " vertical"
xmlns: app= " http://schemas.android.com/apk/res-auto"
android: background= " #F0F4F7" >
< androidx.constraintlayout.widget.ConstraintLayout
android: id= " @+id/constraintLayout"
android: layout_width= " match_parent"
android: layout_height= " 40dp"
app: layout_constraintTop_toTopOf= " parent" >
< ImageView
android: id= " @+id/btn_back"
android: layout_width= " 20dp"
android: layout_height= " 20dp"
android: layout_marginLeft= " 15dp"
app: layout_constraintBottom_toBottomOf= " parent"
app: layout_constraintStart_toStartOf= " parent"
app: layout_constraintTop_toTopOf= " parent"
app: srcCompat= " @drawable/nav_back_black" />
< TextView
android: layout_width= " wrap_content"
android: layout_height= " wrap_content"
android: text= " 选择联系人"
android: textColor= " #ff202640"
android: textSize= " 18dp"
app: layout_constraintBottom_toBottomOf= " parent"
app: layout_constraintEnd_toEndOf= " parent"
app: layout_constraintStart_toStartOf= " parent"
app: layout_constraintTop_toTopOf= " parent" />
</ androidx.constraintlayout.widget.ConstraintLayout>
< androidx.recyclerview.widget.RecyclerView
android: id= " @+id/rcvContractList"
android: layout_width= " match_parent"
android: layout_height= " 0dp"
app: layout_constraintBottom_toBottomOf= " parent"
app: layout_constraintTop_toBottomOf= " @+id/constraintLayout" />
< com.example.app_contract_people.tools.PinYinSlideView
android: id= " @+id/psvPinyin"
android: layout_width= " wrap_content"
android: layout_height= " 0dp"
app: layout_constraintBottom_toBottomOf= " parent"
app: layout_constraintEnd_toEndOf= " parent"
app: layout_constraintTop_toBottomOf= " @+id/constraintLayout" />
< com.example.app_contract_people.tools.CircleTextView
android: id= " @+id/ctvPinyin"
android: layout_width= " 80dp"
android: layout_height= " 80dp"
app: layout_constraintBottom_toBottomOf= " parent"
app: layout_constraintEnd_toEndOf= " parent"
app: layout_constraintStart_toStartOf= " parent"
app: layout_constraintTop_toTopOf= " parent" />
</ androidx.constraintlayout.widget.ConstraintLayout>
< ? xml version= "1.0" encoding= "utf-8" ? >
< LinearLayout xmlns: android= "http://schemas.android.com/apk/res/android"
xmlns: app= "http://schemas.android.com/apk/res-auto"
xmlns: tools= "http://schemas.android.com/tools"
android: layout_width= "match_parent"
android: layout_height= "wrap_content"
android: orientation= "vertical" >
< LinearLayout
android: id= "@+id/stick_container"
android: visibility= "gone"
android: orientation= "vertical"
android: layout_width= "match_parent"
android: layout_height= "40dp"
android: gravity= "center_vertical" >
< TextView
android: id= "@+id/header"
android: text= "A"
android: textSize= "20sp"
android: layout_marginLeft= "20dp"
android: layout_width= "wrap_content"
android: layout_height= "wrap_content" / >
< / LinearLayout >
< LinearLayout
android: layout_width= "match_parent"
android: layout_height= "56dp"
android: background= "@color/white"
android: gravity= "center_vertical"
android: orientation= "horizontal" >
< ImageView
android: id= "@+id/ivCheck"
android: layout_width= "20dp"
android: layout_height= "20dp"
android: layout_marginLeft= "15dp"
android: background= "@drawable/selector_telcheck"
android: paddingLeft= "15dp"
android: visibility= "visible"
app: layout_constraintBottom_toBottomOf= "parent"
app: layout_constraintLeft_toLeftOf= "parent"
app: layout_constraintTop_toTopOf= "parent" / >
< de. hdodenhof. circleimageview. CircleImageView
android: id= "@+id/civHead"
android: layout_width= "48dp"
android: layout_height= "48dp"
android: layout_marginLeft= "15dp" / >
< TextView
android: id= "@+id/tvName"
android: layout_width= "wrap_content"
android: layout_height= "wrap_content"
android: layout_marginLeft= "12dp"
android: text= "A-曾薇"
android: textColor= "#ff4d5b99"
android: textSize= "16dp" / >
< / LinearLayout >
< / LinearLayout >
4.创建工具类
package com. example. app_contract_people. tools ;
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. exception. BadHanyuPinyinOutputFormatCombination ;
import java. util. ArrayList ;
import java. util. Hashtable ;
import java. util. List ;
import java. util. Map ;
public class Pinyin4jUtil {
public static String convertToFirstSpell ( String chinese) {
StringBuffer pinyinName = new StringBuffer ( ) ;
char [ ] nameChar = chinese. toCharArray ( ) ;
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat ( ) ;
defaultFormat. setCaseType ( HanyuPinyinCaseType . UPPERCASE) ;
defaultFormat. setToneType ( HanyuPinyinToneType . WITHOUT_TONE) ;
for ( char c : nameChar) {
if ( c > 128 ) {
try {
String [ ] strs = PinyinHelper . toHanyuPinyinStringArray ( c, defaultFormat) ;
if ( strs != null ) {
for ( int i = 0 ; i < strs. length; i++ ) {
pinyinName. append ( strs[ i] . charAt ( 0 ) ) ;
if ( i != strs. length - 1 ) {
pinyinName. append ( "," ) ;
}
}
}
} catch ( BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination. printStackTrace ( ) ;
}
} else {
pinyinName. append ( c) ;
}
pinyinName. append ( " " ) ;
}
return parseTheChineseByObject ( discountTheChinese ( pinyinName. toString ( ) ) ) ;
}
public static String convertToSpell ( String chinese) {
StringBuffer pinyinName = new StringBuffer ( ) ;
char [ ] nameChar = chinese. toCharArray ( ) ;
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat ( ) ;
defaultFormat. setCaseType ( HanyuPinyinCaseType . LOWERCASE) ;
defaultFormat. setToneType ( HanyuPinyinToneType . WITHOUT_TONE) ;
for ( char c : nameChar) {
if ( c > 128 ) {
try {
String [ ] strs = PinyinHelper . toHanyuPinyinStringArray ( c, defaultFormat) ;
if ( strs != null ) {
for ( int i = 0 ; i < strs. length; i++ ) {
pinyinName. append ( strs[ i] ) ;
if ( i != strs. length - 1 ) {
pinyinName. append ( "," ) ;
}
}
}
} catch ( BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination. printStackTrace ( ) ;
}
} else {
pinyinName. append ( c) ;
}
pinyinName. append ( " " ) ;
}
return parseTheChineseByObject ( discountTheChinese ( pinyinName. toString ( ) ) ) ;
}
public static List < String > convertToSpellList ( String chinese) {
StringBuffer pinyinName = new StringBuffer ( ) ;
char [ ] nameChar = chinese. toCharArray ( ) ;
HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat ( ) ;
defaultFormat. setCaseType ( HanyuPinyinCaseType . LOWERCASE) ;
defaultFormat. setToneType ( HanyuPinyinToneType . WITHOUT_TONE) ;
for ( char c : nameChar) {
if ( c > 128 ) {
try {
String [ ] strs = PinyinHelper . toHanyuPinyinStringArray ( c, defaultFormat) ;
if ( strs != null ) {
for ( int i = 0 ; i < strs. length; i++ ) {
pinyinName. append ( strs[ i] ) ;
if ( i != strs. length - 1 ) {
pinyinName. append ( "," ) ;
}
}
}
} catch ( BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination. printStackTrace ( ) ;
}
} else {
pinyinName. append ( c) ;
}
pinyinName. append ( " " ) ;
}
return parseTheChineseByObjectToList ( discountTheChinese ( pinyinName. toString ( ) ) ) ;
}
private static List < Map < String , Integer > > discountTheChinese ( String theStr) {
List < Map < String , Integer > > mapList = new ArrayList < Map < String , Integer > > ( ) ;
Map < String , Integer > onlyOne = null ;
String [ ] firsts = theStr. split ( " " ) ;
for ( String str : firsts) {
onlyOne = new Hashtable < String , Integer > ( ) ;
String [ ] china = str. split ( "," ) ;
for ( String s : china) {
Integer count = onlyOne. get ( s) ;
if ( count == null ) {
onlyOne. put ( s, new Integer ( 1 ) ) ;
} else {
onlyOne. remove ( s) ;
count++ ;
onlyOne. put ( s, count) ;
}
}
mapList. add ( onlyOne) ;
}
return mapList;
}
private static String parseTheChineseByObject ( List < Map < String , Integer > > list) {
Map < String , Integer > first = null ;
for ( int i = 0 ; i < list. size ( ) ; i++ ) {
Map < String , Integer > temp = new Hashtable < String , Integer > ( ) ;
if ( first != null ) {
for ( String s : first. keySet ( ) ) {
for ( String s1 : list. get ( i) . keySet ( ) ) {
String str = s + s1;
temp. put ( str, 1 ) ;
}
}
if ( temp != null && temp. size ( ) > 0 ) {
first. clear ( ) ;
}
} else {
for ( String s : list. get ( i) . keySet ( ) ) {
String str = s;
temp. put ( str, 1 ) ;
}
}
if ( temp != null && temp. size ( ) > 0 ) {
first = temp;
}
}
String returnStr = "" ;
List < String > returnList = new ArrayList < > ( ) ;
if ( first != null ) {
for ( String str : first. keySet ( ) ) {
returnStr += ( str + " " ) ;
returnList. add ( str) ;
}
}
if ( returnStr. length ( ) > 0 ) {
returnStr = returnStr. substring ( 0 , returnStr. length ( ) - 1 ) ;
}
return returnList. get ( 0 ) ;
}
private static List < String > parseTheChineseByObjectToList ( List < Map < String , Integer > > list) {
Map < String , Integer > first = null ;
for ( int i = 0 ; i < list. size ( ) ; i++ ) {
Map < String , Integer > temp = new Hashtable < String , Integer > ( ) ;
if ( first != null ) {
for ( String s : first. keySet ( ) ) {
for ( String s1 : list. get ( i) . keySet ( ) ) {
String str = s + s1;
temp. put ( str, 1 ) ;
}
}
if ( temp != null && temp. size ( ) > 0 ) {
first. clear ( ) ;
}
} else {
for ( String s : list. get ( i) . keySet ( ) ) {
String str = s;
temp. put ( str, 1 ) ;
}
}
if ( temp != null && temp. size ( ) > 0 ) {
first = temp;
}
}
List < String > returnList = new ArrayList < > ( ) ;
if ( first != null ) {
for ( String str : first. keySet ( ) ) {
returnList. add ( str) ;
}
}
return returnList;
}
public static boolean isPinYin ( String string) {
char [ ] chars = string. toCharArray ( ) ;
for ( char c : chars) {
if ( ( c >= 65 && c <= 90 ) || ( c >= 97 && c <= 122 ) ) {
} else {
return false ;
}
}
return true ;
}
}
package com. example. app_contract_people. tools ;
import com. example. app_contract_people. bean. Person ;
import java. util. Comparator ;
public class PinYinComparator implements Comparator < Person > {
@Override
public int compare ( Person o1, Person o2) {
if ( o1. getPinyin ( ) . equals ( "#" ) ) {
return 1 ;
} else if ( o2. getPinyin ( ) . equals ( "#" ) ) {
return - 1 ;
}
return o1. getPinyin ( ) . compareToIgnoreCase ( o2. getPinyin ( ) ) ;
}
}
5.使用工具类,形成按字母分类效果
package com. example. app_contract_people ;
import androidx. annotation. NonNull ;
import androidx. appcompat. app. AppCompatActivity ;
import androidx. recyclerview. widget. LinearLayoutManager ;
import androidx. recyclerview. widget. RecyclerView ;
import android. os. Bundle ;
import android. text. TextUtils ;
import android. view. LayoutInflater ;
import android. view. View ;
import android. view. ViewGroup ;
import android. widget. ImageView ;
import android. widget. LinearLayout ;
import android. widget. TextView ;
import com. bumptech. glide. Glide ;
import com. example. app_contract_people. bean. Person ;
import com. example. app_contract_people. tools. CircleTextView ;
import com. example. app_contract_people. tools. PinYinComparator ;
import com. example. app_contract_people. tools. PinYinSlideView ;
import com. example. app_contract_people. tools. Pinyin4jUtil ;
import java. io. BufferedReader ;
import java. io. IOException ;
import java. io. InputStream ;
import java. io. InputStreamReader ;
import java. util. ArrayList ;
import java. util. Collections ;
import java. util. List ;
public class MainActivity extends AppCompatActivity {
List < Person > arraylist = new ArrayList < > ( ) ;
MyAdapter myAdapter;
RecyclerView rcvContractList;
Boolean flag = false ;
PinYinSlideView psvPinyin;
CircleTextView ctvPinyin;
int mIndex;
boolean move;
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R . layout. activity_main) ;
psvPinyin = findViewById ( R . id. psvPinyin) ;
ctvPinyin = findViewById ( R . id. ctvPinyin) ;
rcvContractList = findViewById ( R . id. rcvContractList) ;
myAdapter = new MyAdapter ( ) ;
rcvContractList. setAdapter ( myAdapter) ;
LinearLayoutManager lm = new LinearLayoutManager ( this ) ;
rcvContractList. setLayoutManager ( lm) ;
for ( int i = 0 ; i < 20 ; i++ ) {
Person p = new Person ( ) ;
p. setAccount ( "测试" + i) ;
p. setIs_check ( true ) ;
p. setHeaderUrl ( "https://img-blog.csdnimg.cn/20200614120050920.JPG" ) ;
p. setPinyin ( Pinyin4jUtil . convertToFirstSpell ( p. getAccount ( ) ) ) ;
arraylist. add ( p) ;
}
arraylist. addAll ( getPersonList ( ) ) ;
}
class MyAdapter extends RecyclerView. Adapter < MyViewHolder > {
@NonNull
@Override
public MyViewHolder onCreateViewHolder ( @NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater . from ( MainActivity . this ) . inflate ( R . layout. item_contract_list, parent, false ) ;
MyViewHolder myViewHolder = new MyViewHolder ( view) ;
return myViewHolder;
}
@Override
public void onBindViewHolder ( @NonNull MyViewHolder holder, int position) {
Person person = arraylist. get ( position) ;
holder. tvName. setText ( person. getAccount ( ) ) ;
holder. ivCheck. setSelected ( person. getIs_check ( ) ) ;
Glide . with ( MainActivity . this ) . load ( person. getHeaderUrl ( ) ) . into ( holder. ivHead) ;
if ( position == 0 ) {
holder. llPinyin. setVisibility ( View . VISIBLE) ;
holder. tvPinyin. setText ( person. getFirstPinyin ( ) ) ;
} else {
if ( ! TextUtils . equals ( person. getFirstPinyin ( ) , arraylist. get ( position - 1 ) . getFirstPinyin ( ) ) ) {
holder. llPinyin. setVisibility ( View . VISIBLE) ;
holder. tvPinyin. setText ( person. getFirstPinyin ( ) ) ;
} else {
holder. llPinyin. setVisibility ( View . GONE) ;
}
}
holder. itemView. setContentDescription ( person. getFirstPinyin ( ) ) ;
}
@Override
public int getItemCount ( ) {
return arraylist. size ( ) ;
}
}
class MyViewHolder extends RecyclerView. ViewHolder {
LinearLayout llPinyin;
TextView tvPinyin;
ImageView ivCheck;
ImageView ivHead;
TextView tvName;
public MyViewHolder ( @NonNull View itemView) {
super ( itemView) ;
llPinyin = itemView. findViewById ( R . id. stick_container) ;
tvPinyin = itemView. findViewById ( R . id. header) ;
ivCheck = itemView. findViewById ( R . id. ivCheck) ;
ivHead = itemView. findViewById ( R . id. civHead) ;
tvName = itemView. findViewById ( R . id. tvName) ;
}
}
private List < Person > getPersonList ( ) {
List < Person > people = new ArrayList < > ( ) ;
InputStream inputStream = getResources ( ) . openRawResource ( R . raw. names) ;
BufferedReader reader = new BufferedReader ( new InputStreamReader ( inputStream) ) ;
String input = null ;
try {
while ( ( input = reader. readLine ( ) ) != null ) {
Person person = new Person ( ) ;
if ( ! flag) {
person. setIs_check ( false ) ;
person. setHeaderUrl ( "https://img-blog.csdnimg.cn/20200614120050920.JPG" ) ;
flag = true ;
} else {
person. setIs_check ( true ) ;
person. setHeaderUrl ( "https://img-blog.csdnimg.cn/20200614115943345.JPG" ) ;
flag = false ;
}
person. setAccount ( input) ;
String pinyin = Pinyin4jUtil . convertToFirstSpell ( input) ;
if ( Pinyin4jUtil . isPinYin ( pinyin) ) {
person. setPinyin ( pinyin) ;
} else {
person. setPinyin ( "#" ) ;
}
people. add ( person) ;
}
if ( people. size ( ) > 1 ) {
Collections . sort ( people, new PinYinComparator ( ) ) ;
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
return people;
}
}
6.构造数据
从raw中取值,raw的names中放置名字
private List < Person > getPersonList ( ) {
List < Person > people = new ArrayList < > ( ) ;
InputStream inputStream = getResources ( ) . openRawResource ( R . raw. names) ;
BufferedReader reader = new BufferedReader ( new InputStreamReader ( inputStream) ) ;
String input = null ;
try {
while ( ( input = reader. readLine ( ) ) != null ) {
Person person = new Person ( ) ;
if ( ! flag) {
person. setIs_check ( false ) ;
person. setHeaderUrl ( "https://img-blog.csdnimg.cn/20200614120050920.JPG" ) ;
flag = true ;
} else {
person. setIs_check ( true ) ;
person. setHeaderUrl ( "https://img-blog.csdnimg.cn/20200614115943345.JPG" ) ;
flag = false ;
}
person. setAccount ( input) ;
String pinyin = Pinyin4jUtil . convertToFirstSpell ( input) ;
if ( Pinyin4jUtil . isPinYin ( pinyin) ) {
person. setPinyin ( pinyin) ;
} else {
person. setPinyin ( "#" ) ;
}
people. add ( person) ;
}
if ( people. size ( ) > 1 ) {
Collections . sort ( people, new PinYinComparator ( ) ) ;
}
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
return people;
}
for ( int i = 0 ; i < 20 ; i++ ) {
Person p = new Person ( ) ;
p. setAccount ( "测试" + i) ;
p. setIs_check ( true ) ;
p. setHeaderUrl ( "https://img-blog.csdnimg.cn/20200614120050920.JPG" ) ;
p. setPinyin ( Pinyin4jUtil . convertToFirstSpell ( p. getAccount ( ) ) ) ;
arraylist. add ( p) ;
}
实现效果截图