通讯录Demo,持续优化界面

通讯录(联系人信息)实现

例子:利用PinYin4j框架实现通讯录中信息按照开头首字母分类

1.加入依赖

  • build.gradle中加入依赖
    implementation 'de.hdodenhof:circleimageview:3.0.0'//圆形图片
    implementation 'com.github.bumptech.glide:glide:4.6.1'//Glide框架
    compile 'com.belerweb:pinyin4j:2.5.0'//pinyin4j
  • Manifests中加入权限
<!--允许联网 -->
    <uses-permission android:name="android.permission.INTERNET" />

2.创建数据类型

  • Person
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.设置布局

  • activity_main.xml
<?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>
  • item_contract_list.xml
<?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.创建工具类

  • Pinyin4jUtil
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;
    }
}
  • PinYinComparator
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.使用工具类,形成按字母分类效果

  • MainActivity
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);
//        Bmob.initialize(this, "77115099b4d148d8f1b974d32723fc37");

        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) {

           /* Contract contract = arraylist.get(position);
            holder.ivCheck.setSelected(contract.isIs_check());
            holder.tvName.setText(contract.getName());
            Glide.with(MainActivity.this).load(contract.getAvatar()).into(holder.ivHead);*/
            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);
        }
    }

    //从raw文件夹读取数据
    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中放置名字
    在这里插入图片描述
//从raw文件夹读取数据
    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);
        }

实现效果截图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值