精华内容
下载资源
问答
  • 安卓通讯录实现

    千次阅读 2018-05-18 14:29:02
    实现功能 在搜索栏可以搜索通讯录中信息 通讯录可以上下滑动查看通讯录 通讯录索引点击字母后,通讯录自动滑动到指定索引的开始位置 思路 1.需要一个模拟的联系人清单来填充通讯录列表,联系人清单需要按照首...

    通讯录的实现

     

     

    布局设计

    实现功能

    在搜索栏可以搜索通讯录中信息

    通讯录可以上下滑动查看通讯录

    通讯录索引点击字母后,通讯录自动滑动到指定索引的开始位置

     

    思路

    1.需要一个模拟的联系人清单来填充通讯录列表,联系人清单需要按照首字母排序,包含姓名,手机号,头像,首字母信息

    2.把涉及到的首字母存储起来,填充到索引列表里,因为点击索引需要知道通讯录里的位置,所以还需要存储每个字母第一个成员的位置

    3.搜索栏,可以添加对姓名/手机号的搜索,搜索结果放在一个新的列表里

     

    实现步骤

    思路1

    第一步

    布局(最新的AS已经支持了androidx,开发者不用再考虑android的版本了)

    由于没有数据,这里设置了比较醒目的背景色,后期可以取消掉

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout 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="match_parent"
        tools:context=".MainActivity">
    
    
        <androidx.appcompat.widget.SearchView
            android:id="@+id/search"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:text="搜索栏"
            android:textSize="18sp"
            android:background="@android:color/holo_blue_dark"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:ignore="HardcodedText" />
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="32dp"
            android:layout_marginBottom="8dp"
            android:background="@android:color/holo_orange_dark"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/search" />
    
        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            android:background="@android:color/holo_green_dark"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/recyclerView"
            app:layout_constraintTop_toBottomOf="@+id/search" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    页面效果

     

    第二步

    准备我们的联系人清单

    这里我构造了一个自己的联系人对象,as中有快捷键,可以帮助我们快速创建对象的构造器和get/set方法,alt+insert方法

    public class Contact {
        private String mFirstLetter;
        private String mName;
        private String mPhone;
        private String mPicUrl;
    
        public Contact(String firstLetter, String name, String phone, String picUrl) {
            mFirstLetter = firstLetter;
            mName = name;
            mPhone = phone;
            mPicUrl = picUrl;
        }
    
        public String getFirstLetter() {
            return mFirstLetter;
        }
    
        public void setFirstLetter(String firstLetter) {
            mFirstLetter = firstLetter;
        }
    
        public String getName() {
            return mName;
        }
    
        public void setName(String name) {
            mName = name;
        }
    
        public String getPhone() {
            return mPhone;
        }
    
        public void setPhone(String phone) {
            mPhone = phone;
        }
    
        public String getPicUrl() {
            return mPicUrl;
        }
    
        public void setPicUrl(String picUrl) {
            mPicUrl = picUrl;
        }
    }

    然后在主活动中初始化我们的联系人

    private List<Contact>mContactList;
    
    ......
    
    private void initContactList() {
            mContactList=new ArrayList<>();
            mContactList.add(new Contact("A","阿黄","13013013011","https://cdn.duitang.com/uploads/item/201508/02/20150802155755_YCynL.thumb.700_0.jpeg"));
            mContactList.add(new Contact("A","阿芳","14014014011","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=4259300811,497831842&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("B","宝宝","15015015011","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=4285611627,3487298056&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("D","弟弟","16016016011","https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1700741544,1951185347&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("G","哥哥","17017017011","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3358148341,156066392&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("J","姐姐","18018018011","https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=2402471065,951299553&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("M","妈妈","19019019011","https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=399600612,252901190&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("M","妹妹","12012012011","https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1466662081,1140396699&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("W","忘了名字","15015015012","https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3361934473,3725527506&fm=26&gp=0.jpg"));
            mContactList.add(new Contact("X","小强","15015015013","https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=4016536275,4119245052&fm=26&gp=0.jpg"));
        }

    头像采用的是百度图片找到的地址,稍后会加载网络图片的形式加载头像

    第三步

    填充我们的RecycleView

    需要我们先设置一个布局,命名为contact_item

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout 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">
    
        <View
            android:id="@+id/view"
            android:layout_width="0dp"
            android:layout_height="20dp"
            android:background="#DDDDDD"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <ImageView
            android:id="@+id/pic"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="32dp"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:ignore="ContentDescription"
            tools:srcCompat="@tools:sample/backgrounds/scenic" />
    
        <TextView
            android:id="@+id/name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            android:layout_marginTop="8dp"
            app:layout_constraintStart_toEndOf="@+id/pic"
            app:layout_constraintTop_toTopOf="@+id/pic"
            tools:text="阿黄" />
    
        <TextView
            android:id="@+id/phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="32dp"
            android:layout_marginTop="16dp"
            app:layout_constraintStart_toEndOf="@+id/pic"
            app:layout_constraintTop_toBottomOf="@+id/name"
            tools:text="15015015011" />
    
        <TextView
            android:id="@+id/letter"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="A" />
    
        <View
            android:layout_width="0dp"
            android:layout_height="1dp"
            android:background="#DDDDDD"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>

    页面效果

    接下来需要定义一个我们自己的adapter,这是一个适配器,用来加载我们的数据和界面效果

    这里先继承RecyclerView.Adapter<VH>,VH这里填我们自己的实现类

    public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactHolder>

    在ContactAdapter中实现我们的ViewHolder

    public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactHolder> {
    
        class ContactHolder extends RecyclerView.ViewHolder{
    
            public ContactHolder(@NonNull View itemView) {
                super(itemView);
            }
        }
    
    }

    这个时候直接在ContactAdapter上点击alt+enter,选择implement methods即可直接解决告警,帮我们添加了必要的需要自己家实现的方法

    由于adapter需要保存所有的联系人信息,这里需要我们添加一个联系人列表,并设置构造器

        private List<Contact> mContactList;
    
        public ContactAdapter(List<Contact> contactList) {
            mContactList = contactList;
        }

    然后实现我们自己的方法即可

    下面是完整的代码,加载图片用到了Glide,因为需要网络加载图片,所以记得在配置文件加上网络权限

    public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactHolder> {
    
        private List<Contact> mContactList;
    
        public ContactAdapter(List<Contact> contactList) {
            mContactList = contactList;
        }
    
        @NonNull
        @Override
        public ContactHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.contact_item,parent,false);
            return new ContactHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull ContactHolder holder, int position) {
            Contact data=mContactList.get(position);
            holder.mLetter.setText(data.getFirstLetter());
            holder.mName.setText(data.getName());
            holder.mPhone.setText(data.getPhone());
            Glide.with(holder.mPic.getContext()).load(data.getPicUrl()).into(holder.mPic);
        }
    
        @Override
        public int getItemCount() {
            return mContactList.size();
        }
    
        class ContactHolder extends RecyclerView.ViewHolder{
    
            private TextView mLetter;
            private TextView mName;
            private TextView mPhone;
            private ImageView mPic;
            public ContactHolder(@NonNull View itemView) {
                super(itemView);
                mName=itemView.findViewById(R.id.name);
                mLetter=itemView.findViewById(R.id.letter);
                mPhone=itemView.findViewById(R.id.phone);
                mPic=itemView.findViewById(R.id.pic);
            }
        }
    }

    然后加载我们的adpater吧

    @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mSearch=findViewById(R.id.search);
            mRecyclerView=findViewById(R.id.recyclerView);
            mRecyclerView2=findViewById(R.id.recyclerView2);
            initContactList();
            initContactRecyclerView();
        }
    
        private void initContactRecyclerView() {
            LinearLayoutManager manager=new LinearLayoutManager(this,RecyclerView.VERTICAL,false);
            mRecyclerView.setLayoutManager(manager);
            ContactAdapter adapter=new ContactAdapter(mContactList);
            mRecyclerView.setAdapter(adapter);
        }

    效果如下

    这里有完善的地方,首字母最好不要重复出现,比如阿黄和阿芳,标题a出现1次就可以了

    不过这里只提供思路,不再讲如何实现。在contact中添加是否需要显示首字母的属性,比较contacList前后两个成员的letter,相同就把第二个成员的隐藏属性打开,在adapter的onBind方法中,隐藏标题栏即可

     

    思路2

    这里,我们需要拿到联系人清单里出现过的首字母,以及对应第一个首字母联系人在通讯录中的位置

    private List<String> mLetterList;
    private List<Integer> mletterPosition;
    ......
    
    private void initLetterList() {
            mLetterList=new ArrayList<>();
            mletterPosition=new ArrayList<>();
            int index=0;
            for (Contact data :
                 mContactList) {
                if (!mLetterList.contains(data.getFirstLetter())){
                   mLetterList.add(data.getFirstLetter());
                   mletterPosition.add(index);
                }
                index++;
            }
            
        }

     

    接下来写一个letter_item

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout 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">
    
        <TextView
            android:id="@+id/letter"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:text="A" />
    </androidx.constraintlayout.widget.ConstraintLayout>

    宽度我设置为了自适应

    然后是我们的letterAdapter

    public class LetterAdapter extends RecyclerView.Adapter<LetterAdapter.LetterHolder> {
    
        private List<String> letterList;
        private List<Integer> letterPosition;
    
    
        public LetterAdapter(List<String> letterList, List<Integer> letterPosition) {
            this.letterList = letterList;
            this.letterPosition = letterPosition;
        }
    
        @NonNull
        @Override
        public LetterHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.letter_item,parent,false);
            return new LetterHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull LetterHolder holder, int position) {
            holder.mLetter.setText(letterList.get(position));
        }
    
        @Override
        public int getItemCount() {
            return letterList.size();
        }
    
        class LetterHolder extends RecyclerView.ViewHolder{
    
            private TextView mLetter;
            public LetterHolder(@NonNull View itemView) {
                super(itemView);
                mLetter=itemView.findViewById(R.id.letter);
            }
        }
    }

    加载列表

    private void initLetterRecyclerView() {
            LinearLayoutManager manager=new LinearLayoutManager(this,RecyclerView.VERTICAL,false);
            mRecyclerView2.setLayoutManager(manager);
            LetterAdapter adapter=new LetterAdapter(mLetterList,mletterPosition);
            mRecyclerView2.setAdapter(adapter);
        }

    实现效果

     

    第二步就是如何让我们的字母索引,点击后,可以让联系人滑动到我们指定的位置

    我们已经知道了字母索引对应的位置,可以直接在点击事件里让联系人的REcyclerView通过SmoothScrollToPositon()方法滑动到我们的指定位置即可

    LetterAdapter中的onbind方法

    @Override
        public void onBindViewHolder(@NonNull LetterHolder holder, final int position) {
            holder.mLetter.setText(letterList.get(position));
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mRecyclerView.smoothScrollToPosition(letterPosition.get(position));
                }
            });
        }

    扩展:

    这里,多点击会发现SmoothScrollToPositon()方法的实现效果有些让我不满意的地方,向下滑动,会让目标位置,出现在页面最下方,而不是页面最上方。不过这个问题可以以后解决

     

    思路3

    这里实现的效果是,打开搜索栏,会隐藏联系人列表和索引表,对搜索内容,通过正则表达式,对姓名和电话号码筛选出可能需要的联系人,添加到searchView中,然后设置一个新的RecyclerView,并填充数据

    当关闭searchView时,会重新显示所有联系人

        private RecyclerView mRecyclerView3;
        private List<Contact> searchResult;
        ...
        
        protected void onCreate(Bundle savedInstanceState) {
        ...
        mRecyclerView3=findViewById(R.id.recyclerView3);
        LinearLayoutManager manager=new LinearLayoutManager(this,RecyclerView.VERTICAL,false);
            mRecyclerView3.setLayoutManager(manager);
        ...
        initSearchView();
        }
    
    private void initSearchView() {
            mSearch.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    return false;
                }
    
                @Override
                public boolean onQueryTextChange(String newText) {
                    searchResult=new ArrayList<>();
                    if(mRecyclerView.getVisibility()== View.VISIBLE){
                        mRecyclerView.setVisibility(View.GONE);
                        mRecyclerView2.setVisibility(View.GONE);
                        mRecyclerView3.setVisibility(View.VISIBLE);
                    }
                    String regx="[\\u0391-\\uFFE5]*";
                    String newTextRegx="[\\u0391-\\uFFE5]*";
                    for (int j=0;j<newText.length();j++){
                        String temp=newTextRegx;
                        newTextRegx=temp+newText.charAt(j)+regx;
                    }
                    String regx2="[0-9]*";
                    String newTextRegx2="[0-9]*";
                    for (int j=0;j<newText.length();j++){
                        String temp=newTextRegx2;
                        newTextRegx2=temp+newText.charAt(j)+regx2;
                    }
                    Log.i("newTextRegx2=", newTextRegx2);
                    Log.i("newTextRegx1=", newTextRegx);
                    for (Contact data :
                            mContactList) {
                        if (data.getName().matches(newTextRegx)){
                            searchResult.add(data);
                            Log.i("add", data.getName());
                        }else if (data.getPhone().matches(newTextRegx2)){
                            searchResult.add(data);
                            Log.i("add", data.getPhone());
                        }
                    }
    
                    ContactAdapter adapter=new ContactAdapter(searchResult);
                    mRecyclerView3.setAdapter(adapter);
                    return true;
                }
            });
            mSearch.setOnCloseListener(new SearchView.OnCloseListener() {
                @Override
                public boolean onClose() {
                   mRecyclerView.setVisibility(View.VISIBLE);
                   mRecyclerView2.setVisibility(View.VISIBLE);
                   mRecyclerView3.setVisibility(View.GONE);
                    return false;
                }
            });
        }

    附上源地址

    github contactList_java

    https://github.com/wwqby/ContactList_java.git

    再往下面,就是老版本的联系人以及一些补充的知识点,就放在这里,有时间再整理

     

     

     

    其次,实现代码部分

    一文件清单

    由于adapter大同小异,这里略过

    1数据文件

    Contacts类

    
    public class Contacts implements Comparable<Contacts>{
        private String name;
        private String teleNumber;
        private String position;
        private int headPicId;
        private String spelling;
        private boolean isFirst=false;
    
        public Contacts(String name, String teleNumber, String position,int headPicId,CharacterParser characterParser) {
            this.name = name;
            this.teleNumber = teleNumber;
            this.position=position;
            this.headPicId = headPicId;
            characterParser.setResource(name);//通过拼音转换类,把汉字转换成拼音//
            this.spelling=characterParser.getSpelling();
        }
    
        public String getName() {
            return name;
        }
    
        public String getTeleNumber() {
            return teleNumber;
        }
    
        public String getPosition() {
            return position;
        }
    
        public int getHeadPicId() {
            return headPicId;
        }
    
        public String getSpelling() {
            return spelling;
        }
    
        public boolean getIsFirst() {
            return isFirst;
        }
    
        public void setIsFirst(boolean isFirst) {
            this.isFirst = isFirst;
        }
    
        @Override
        public int compareTo(@NonNull Contacts o) {
            return this.spelling.compareTo(o.spelling);
        }
    
        @Override
        public String toString() {
            String name=getName();
    
            return "name="+name+",isFirst="+isFirst;
        }
    }

    关于比较排序,Java中有Comparable接口(实现compareTo()方法)和Comparator类两种方法

    参考资料

    https://www.cnblogs.com/Kevin-mao/p/5912775.html

    这里是让Contact实现了Compareable接口

    对于List<Contact> list,直接调用Conllections.sort(list),即可获得排序后的list.

    2.LetterData类

    public class LetterData {
        private String letter;
        private int position;//记录首次出现首字母的RecyclerView中的位置//
    
        public LetterData(String letter, int position) {
            this.letter = letter;
            this.position = position;
        }
    
        public String getLetter() {
            return letter;
        }
    
        public void setLetter(String letter) {
            this.letter = letter;
        }
    
        public int getPosition() {
            return position;
        }
    
        public void setPosition(int position) {
            this.position = position;
        }
    
        @Override
        public String toString() {
            return "letter="+getLetter()+",position="+getPosition();
        }
    }
    

    3.拼音转换类

     资料

    https://blog.csdn.net/xiaanming/article/details/12684155

    如何从汉字获得拼音以及首字母

    受益于资料中作者的工作,首先把汉字转换成GB2312码,然后根据GB2312的编码原则转成ASC2码,然后根据固定的汉语拼音构成,以及其对应的ASC2码库,从ASC2码转换成汉语拼音

    public class CharacterParser {
        private static int[] pyvalue = new int[]{-20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, -20230, -20051, -20036, -20032,
                -20026, -20002, -19990, -19986, -19982, -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, -19741, -19739, -19728,
                -19725, -19715, -19540, -19531, -19525, -19515, -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, -19263, -19261,
                -19249, -19243, -19242, -19238, -19235, -19227, -19224, -19218, -19212, -19038, -19023, -19018, -19006, -19003, -18996, -18977, -18961,
                -18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, -18731, -18722, -18710, -18697, -18696, -18526, -18518, -18501, -18490,
                -18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, -18211, -18201, -18184, -18183, -18181, -18012, -17997, -17988,
                -17970, -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, -17733, -17730, -17721, -17703, -17701, -17697, -17692,
                -17683, -17676, -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, -17185, -16983, -16970, -16942, -16915, -16733,
                -16708, -16706, -16689, -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, -16433, -16429, -16427, -16423, -16419,
                -16412, -16407, -16403, -16401, -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171, -16169, -16158, -16155, -15959,
                -15958, -15944, -15933, -15920, -15915, -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, -15652, -15640, -15631,
                -15625, -15454, -15448, -15436, -15435, -15419, -15416, -15408, -15394, -15385, -15377, -15375, -15369, -15363, -15362, -15183, -15180,
                -15165, -15158, -15153, -15150, -15149, -15144, -15143, -15141, -15140, -15139, -15128, -15121, -15119, -15117, -15110, -15109, -14941,
                -14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, -14914, -14908, -14902, -14894, -14889, -14882, -14873, -14871, -14857,
                -14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, -14429, -14407, -14399, -14384, -14379, -14368, -14355, -14353,
                -14345, -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, -14123, -14122, -14112, -14109, -14099, -14097, -14094,
                -14092, -14090, -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, -13894, -13878, -13870, -13859, -13847, -13831,
                -13658, -13611, -13601, -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, -13359, -13356, -13343, -13340, -13329,
                -13326, -13318, -13147, -13138, -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060, -12888, -12875, -12871, -12860,
                -12858, -12852, -12849, -12838, -12831, -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, -12359, -12346, -12320, -12300,
                -12120, -12099, -12089, -12074, -12067, -12058, -12039, -11867, -11861, -11847, -11831, -11798, -11781, -11604, -11589, -11536, -11358,
                -11340, -11339, -11324, -11303, -11097, -11077, -11067, -11055, -11052, -11045, -11041, -11038, -11024, -11020, -11019, -11018, -11014,
                -10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, -10544, -10533, -10519, -10331, -10329, -10328, -10322, -10315, -10309,
                -10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254};
        public static String[] pystr = new String[]{"a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian",
                "biao", "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "ceng", "cha", "chai", "chan", "chang", "chao", "che",
                "chen", "cheng", "chi", "chong", "chou", "chu", "chuai", "chuan", "chuang", "chui", "chun", "chuo", "ci", "cong", "cou", "cu", "cuan",
                "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du",
                "duan", "dui", "dun", "duo", "e", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
                "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha", "hai", "han", "hang",
                "hao", "he", "hei", "hen", "heng", "hong", "hou", "hu", "hua", "huai", "huan", "huang", "hui", "hun", "huo", "ji", "jia", "jian",
                "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan", "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "ken",
                "keng", "kong", "kou", "ku", "kua", "kuai", "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng",
                "li", "lia", "lian", "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "lv", "luan", "lue", "lun", "luo", "ma", "mai",
                "man", "mang", "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na", "nai",
                "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ni", "nian", "niang", "niao", "nie", "nin", "ning", "niu", "nong", "nu", "nv", "nuan",
                "nue", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng", "pi", "pian", "piao", "pie", "pin", "ping", "po", "pu",
                "qi", "qia", "qian", "qiang", "qiao", "qie", "qin", "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re",
                "ren", "reng", "ri", "rong", "rou", "ru", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sen", "seng", "sha",
                "shai", "shan", "shang", "shao", "she", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui", "shun",
                "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te", "teng", "ti", "tian", "tiao",
                "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan", "wang", "wei", "wen", "weng", "wo", "wu", "xi",
                "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu", "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi",
                "yin", "ying", "yo", "yong", "you", "yu", "yuan", "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha",
                "zhai", "zhan", "zhang", "zhao", "zhe", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui",
                "zhun", "zhuo", "zi", "zong", "zou", "zu", "zuan", "zui", "zun", "zuo"};
        private StringBuilder buffer;
        private String resource;
        private static CharacterParser characterParser = new CharacterParser();
    
        public static CharacterParser getInstance() {
            return characterParser;
        }
    
        public String getResource() {
            return resource;
        }
    
        public void setResource(String resource) {
            this.resource = resource;
        }
    
        /**
         * 汉字转成ASCII码 * * @param chs * @return
         */
        private int getChsAscii(String chs) {
            int asc = 0;
            try {
                byte[] bytes = chs.getBytes("GB2312");
                if (bytes == null || bytes.length > 2 || bytes.length <= 0) {
                    throw new RuntimeException("illegal resource string");
                }
                if (bytes.length == 1) {
                    asc = bytes[0];
                }
                if (bytes.length == 2) {
                    int hightByte = 256 + bytes[0];
                    int lowByte = 256 + bytes[1];
                    asc = (256 * hightByte + lowByte) - 256 * 256;
                }
            } catch (Exception e) {
                System.out.println("ERROR:ChineseSpelling.class-getChsAscii(String chs)" + e);
            }
            return asc;
        }
    
        /**
         * 单字解析 * * @param str * @return
         */
        public String convert(String str) {
            String result = null;
            int ascii = getChsAscii(str);
            if (ascii > 0 && ascii < 160) {
                result = String.valueOf((char) ascii);
            } else {
                for (int i = (pyvalue.length - 1); i >= 0; i--) {
                    if (pyvalue[i] <= ascii) {
                        result = pystr[i];
                        break;
                    }
                }
            }
            return result;
        }
    
        /**
         * 词组解析 * * @param chs * @return
         */
        public String getSelling(String chs) {
            String key, value;
            buffer = new StringBuilder();
            for (int i = 0; i < chs.length(); i++) {
                key = chs.substring(i, i + 1);
                if (key.getBytes().length >= 2) {
                    value = (String) convert(key);
                    if (value == null) {
                        value = "unknown";
                    }
                } else {
                    value = key;
                }
                buffer.append(value);
            }
            return buffer.toString();
        }
    
        public String getSpelling() {
            return this.getSelling(this.getResource());
        }
    
    }

    关于gb2312,参考

    http://xuepengcheng.iteye.com/blog/854739

    https://www.cnblogs.com/hehheai/p/6510879.html

    gb2312首先判断byte的最高位,0,本字节就是ASC2码;1,则取两个字节作为1个汉字。这两个字节的最高位代表符号为负,即height=256+btye[0],lower=256+byte[1],取剩下的7位,然后height*256+lower,然后我猜测可能是需要取补码,所以需要减去256*256,即pinyinvalue字库的来源

    4活动文件

    public class ContactsFragment extends Fragment{
    
        @BindView(R.id.sv_search_contacts)
        SearchView svSearchContacts;
        @BindView(R.id.rv_my_contacts)
        RecyclerView rvMyContacts;
        @BindView(R.id.lv_first_letter)
        ListView lvFirstLetter;
        Unbinder unbinder;
    
    
       //Rv填充的联系人列表
        private List<Contacts> contactsList = new ArrayList<>();
        //Lv填充的首字母清单
        private List<String> letterList=new ArrayList<>();
        //lv真正填充的首字母列表
        private List<LetterData> letterDataList=new ArrayList<>();
    
    //    拼音工具类实例
        private CharacterParser characterParser=CharacterParser.getInstance();
        private String TAG = "ContactsFragment";
    //    RV滚动监听需要的布局管理器
        private LinearLayoutManager linear;
    //    RV滚动监听的标志位
        private boolean move=false;
    //    RV滚动监听的目的位置
        private int toPosition;
    
    
        public ContactsFragment() {
            // Required empty public constructor
        }
    
        public static ContactsFragment newInstance() {
            ContactsFragment fragment = new ContactsFragment();
            Bundle args = new Bundle();
            fragment.setArguments(args);
            return fragment;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    //        TODO test
            contactsList.add(new Contacts("王小明","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("王大明","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("陈文山","15001243836","组长",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("方文山","15001243836","组长",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("张鹏","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("张大大","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("李业辉","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("李登","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("尤利","15001243836","组员",R.drawable.pressed,characterParser));
            contactsList.add(new Contacts("尤东升","15001243836","组员",R.drawable.pressed,characterParser));
    //          排序
            Collections.sort(contactsList);
            LogUtil.i(TAG, "onCreate: "+contactsList.toString());
    //          初始化letterDataList
            letterDataList=initLetterList(contactsList);
        }
    
        private List<LetterData> initLetterList(List<Contacts> contactsList) {
            for (int i=0;i<contactsList.size();i++){
                String letter=contactsList.get(i).getSpelling().substring(0,1).toUpperCase();
                LogUtil.i(TAG, "initLetterList: letter="+letter);
                if (!letterList.contains(letter)){
                    letterList.add(letter);
                    LetterData letterData=new LetterData(letter,i);
                    letterDataList.add(letterData);
                    contactsList.get(i).setIsFirst(true);
                    LogUtil.i(TAG, "initLetterList: position="+i);
                }
            }
            LogUtil.i(TAG, "initLetterList: letterList="+letterList.toString());
            LogUtil.i(TAG, "initLetterList: letterDataList="+letterDataList.toString());
            LogUtil.i(TAG, "initLetterList: contactsList="+contactsList.toString());
            return letterDataList;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            // Inflate the layout for this fragment
            View view = inflater.inflate(R.layout.fragment_contacts, container, false);
            unbinder = ButterKnife.bind(this, view);
    //          为RV和LV加载数据
            linear=new LinearLayoutManager(getContext(),LinearLayoutManager.VERTICAL,false);
            rvMyContacts.setLayoutManager(linear);
            ContactsAdapter adapter=new ContactsAdapter(contactsList);
            rvMyContacts.setAdapter(adapter);
            LetterDataAdapter adapter2=new LetterDataAdapter(getContext(),R.layout.layout_letter,letterDataList);
            lvFirstLetter.setAdapter(adapter2);
    //        初始化监听器
            initListener();
    
            return view;
        }
    
        private void initListener() {
            svSearchContacts.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String query) {
                    return false;
                }
    
    //            搜索栏监听
                @Override
                public boolean onQueryTextChange(String newText) {
                    List<Contacts> searchList=new ArrayList<>();
                    if (newText.isEmpty()){
                        searchList=contactsList;
                    }else {
                        for (Contacts contacts:contactsList){
                            if (contacts.getSpelling().contains(newText)){
                                searchList.add(contacts);
                            }
                        }
                    }
                    ContactsAdapter adapter3=new ContactsAdapter(searchList);
                    rvMyContacts.setAdapter(adapter3);
                    return true;
                }
            });
    //        lv的点击监听
            lvFirstLetter.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    LetterData letterData=letterDataList.get(position);
                    toPosition=letterData.getPosition();
                    move(toPosition);
                }
            });
    
    //        滚动监听
            rvMyContacts.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    if (move){
                        move=false;
                        int n=toPosition-linear.findFirstVisibleItemPosition();
                        if (n>0&&n<linear.getChildCount()){
                            int top=rvMyContacts.getChildAt(n).getTop();
                            rvMyContacts.smoothScrollBy(0,top);
                        }
                    }
                }
            });
        }
    
    //    lv点击中的move()方法,主要是重用了smoothScrollBy()方法
        private void move(int position) {
            int first=linear.findFirstVisibleItemPosition();
            int last=linear.findLastVisibleItemPosition();
            LogUtil.i(TAG, "move: position="+position);
            LogUtil.i(TAG, "move: first="+first);
            LogUtil.i(TAG, "move: last="+last);
            if (position<first){
                rvMyContacts.smoothScrollToPosition(position);
                LogUtil.i(TAG, "move: first front");
            }else if (position<=last){
                int top=rvMyContacts.getChildAt(position-first).getTop();
                rvMyContacts.smoothScrollBy(0,top);
                LogUtil.i(TAG, "move: top="+top);
            }else if (position>last){
                rvMyContacts.smoothScrollToPosition(position);
                move=true;
                LogUtil.i(TAG, "move: last-first="+(last-first));
            }
        }
    
    
        @Override
        public void onDestroyView() {
            super.onDestroyView();
            unbinder.unbind();
        }
    }

    最后是实现效果(不会上传gif图片)

     

     

    填坑

    1,通讯录中字母分组的角标,会出现混乱的情况

    这种情况是因为Recyclerview本身的复用机制产生的.

    角标的visibility属性在xml中默认为gone,

    代码中设置角标时打开,visibility设置为visible

    即使后续有item的角标代码中没有设置visibility属性,复用机制也会出现错位的角标

    解决办法,代码中需要手动设置判断需要显示的显示,不需要显示的设置visibility为gone

    参考https://segmentfault.com/q/1010000006217554?sort=created

     

    2.实现过程中遇到的新的函数

    RecyclerView.scrollToPosition(int i)直接定位滚动到指定的item位置

    滚动方向:item相对于当前显示的item而定.item在屏幕上方,会从上往下滚动,直到item变成显示的第一条;item在屏幕中,不滚动;item在屏幕下方,从下往上滚动,item变成最后一条.

    RecyclerView.smoothScrollToPosition(int i)增加平滑滚动的视觉效果,定位滚动到指定的item位置

    RecyclerView.scrollBy(int x,int y) 按给定的坐标直接滚动到指定的位置

    RecyclerView.SmoothScrollBy(int x,int y) 按给定的坐标直接滚动到指定的位置,增加平滑滚动的效果

    View getChildAt(int index) 在集合中返回指定位置的视图。

    int LayoutManager.findFirstVisibleItemPosition()返回RecyclerView中可见的第一个item的位置

    5 种方法获取 View 的坐标{

            参考https://blog.csdn.net/u013872857/article/details/53750682

        View.getTop()、View.getLeft()、View.getBottom()、View.getRight();用于获取View相对于父容器的坐标

        View.getX()、View.getY();获取的是View左上角相对于父容器的坐标,当View没有发生平移操作时,getX()==getLeft()、getY==getTop()。

        View.getTranslationX()、View.getTranslationY();translationX与 translationY是View左上角相对于父容器的偏移量:translationX = getX() - getLeft(),当View未发生平移操作时,translationX 与translationY都为0。

        View.getLocationOnScreen(int[] position);获取View相对于整个屏幕的坐标。

        View.getLocationInWindow(int[] position);获取View相对于Window的坐标(忽略状态栏及ActionBar)。

    }

     

    3搜索功能

    知识点1 监听搜索栏事件

    处理完事件记得设置return true

    svSearchContacts.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                //按下搜索按钮时,监听事件
                @Override
                public boolean onQueryTextSubmit(String query) {
                    return false;
                }
    
                //搜索栏text改变时监听事件
                @Override
                public boolean onQueryTextChange(String newText) {
                    return false;
                }
            });

    知识点2 正则表达式

    资料参考

    https://www.cnblogs.com/lzq198754/p/5780340.html

    用法: 

    String contact...;
    String TextRegx...;
    if (contact.matches(TextRegx)) {
                                   //do something
                                }

    搜索的实现

    首先判断,字符是字母还是文字(不支持?!这些符号)

    if ( newText.matches("[a-zA-Z]+")){
                            LogUtil.i(TAG, "onQueryTextChange: char");
    }else{
                            LogUtil.i(TAG, "onQueryTextChange: text");
    }

    [a-zA-Z]+代表 字符限制类型为大小写英文字母,+代表[]中的内容至少出现1次

     

    然后,字母搜索的时候,我们希望对全拼中搜索是否包含搜索的字母

    比如libaolong,我们可以搜索这样 lbl,bao,long,等等

    我们需要先把字符串query拆分,在前后填充[a-zA-Z]*  (*代表出现0-无限次,例如a[a-zA-Z]*b,代表ab中间可以出现若干长度的字母字符串,比如ab,aaaab,anmb,...)

                            String regx="[a-zA-Z]*";
                            String newTextRegx="[a-zA-Z]*";
                            for (int j=0;j<newText.length();j++){
                                String temp=newTextRegx;
                                newTextRegx=temp+newText.charAt(j)+regx;
                            }
                            LogUtil.i(TAG, "onQueryTextChange: newTextRegx="+newTextRegx);
                            for (Contact contact : contactsList) {
                                characterParser.setResource(contact.getName());
                                String spell=characterParser.getSpelling();
                                if (spell.matches(newTextRegx)) {
                                    searchList.add(contact);
                                }
                            }

    然而不是字母的时候,我们肯定是希望用汉字来作为关键字搜索

    比如李宝龙,用"李","宝","龙","李龙","宝龙","李宝"来搜索

    对"李"的正则匹配

    [\u0391-\uFFE5]*李[\u0391-\uFFE5]*

                            String regx="[\\u0391-\\uFFE5]*";
                            String newTextRegx="[\\u0391-\\uFFE5]*";
                            for (int j=0;j<newText.length();j++){
                                String temp=newTextRegx;
                                newTextRegx=temp+newText.charAt(j)+regx;
                            }
                            LogUtil.i(TAG, "onQueryTextChange: newTextRegx="+newTextRegx);
                            for (Contact contact : contactsList) {
                                characterParser.setResource(contact.getName());
                                String spell=characterParser.getSpelling();
                                if (contact.getName().matches(newTextRegx)) {
                                    searchList.add(contact);
                                }
                            }

    4 listView去除下划线和背景色

    https://blog.csdn.net/jq_ak47/article/details/52476020

    myListView.setDividerHeight(0);
    
    myListView.setDivider(null);
    
    // XML布局文件中设置ListView的属性
    //或者
    android:divider="@null"
    //设置背景色
    android:cacheColorHint=”#00000000”

    5.滚动监听(实现点击字母索引,跳转指定联系人组)

    首先为字母索引注册点击事件

    lvFirstLetter.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    LetterData letterData = letterDataList.get(position);
                    toPosition = letterData.getPosition();
                    move(toPosition);
                }
            });
    
     //    lv点击中的move()方法,主要是重用了smoothScrollBy()方法
        private void move(int position) {
            int first = linear.findFirstVisibleItemPosition();
            int last = linear.findLastVisibleItemPosition();
            if (position < first) {
                rvMyContacts.smoothScrollToPosition(position);
            } else if (position <= last) {
                int top = rvMyContacts.getChildAt(position - first).getTop();
                rvMyContacts.smoothScrollBy(0, top);
            } else {
                rvMyContacts.smoothScrollToPosition(position);
                move=true;
            }
    
        }
    
    rvMyContacts.addOnScrollListener(new RecyclerView.OnScrollListener() {
    
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    int first = linear.findFirstVisibleItemPosition();
                    View view=rvMyContacts.getChildAt(toPosition - first);
                   if (move&&view!=null){
                       int top= view.getTop();
                       rvMyContacts.smoothScrollBy(0, top);
                       move=false;
                   }
                }
            });

    move分三种情况

    当目标item在当前页面之前,直接滑动到指定item即可

    当目标item在当前页面中,需要计算目标距离第一个可视item的距离,然后通过smoothScrollBy()来移动

    (因为childView的索引是从0开始,所以position-first,就是第position-first+1个item)

    当目标在当前页面之后,先通过smoothScrollTo()命令,会将目标item移动到当前页面最后一个,然后在利用OnScrolled()方法回调,利用move标志位,以及,当目标item存在于当前页面时(view!=null,因为复用机制,只有显示出来的item才存在view),做条件.再次计算目标到顶部的距离,然后通过smoothScrollBy()来滑动到指定位置

     

     

    项目Demo地址

    https://github.com/wwqby/ContactList_java.git

     

    展开全文
  • 安卓简易通讯录

    2013-09-25 10:16:51
    基本实现安卓通讯录功能,有一定参考意义。
  • 通讯录实现

    源码地址

    github地址

    编写代码

    MyDbHelper.java
    package dpHelper;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    import com.example.maibenben.sqlitetest.MainActivity;
    
    /**
     * Created by MAIBENBEN on 2020/5/6.
     */
    public class MyDbHelper extends SQLiteOpenHelper {
        public MyDbHelper(Context context) {
            super(context, "test5.db", null, 1);
            MainActivity.result.append("创建打开库");
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("drop table if exists person");
            db.execSQL("CREATE TABLE person(id INTEGER PRIMARY KEY AUTOINCREMENT,name VARCHAR(20),type VARCHAR(20),imgurl VARCHAR(20))");
            db.execSQL("insert into person values(null,'lxw的爸爸','家人','fish')");
            db.execSQL("insert into person values(null,'lxw的妈妈','家人','queen')");
            db.execSQL("insert into person values(null,'Delta','同学','l4')");
            db.execSQL("insert into person values(null,'DongDong','同学','l5')");
            db.execSQL("insert into person values(null,'栗子','同学','l1')");
            db.execSQL("insert into person values(null,'小明','朋友','l2')");
            MainActivity.result.append("创建打开表");
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    
        }
    }
    
    
    MainActivity.java

    在这里本来是ContractFragment.java,由于下述出现的问题,重建了项目。
    包含数据库的操作
    以及控件的显示与否
    和悬浮图标的监听函数

    package com.example.maibenben.sqlitetest;
    
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.os.Bundle;
    import android.support.design.widget.FloatingActionButton;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.Toolbar;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    
    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.List;
    
    import dpHelper.MyDbHelper;
    
    public class MainActivity extends AppCompatActivity {
        public static StringBuilder result = new StringBuilder("程序的运行结果:");
    
        SQLiteDatabase db;
        Cursor cursor;
    //    private static final String TAG = contactFragment.class.getSimpleName();
    
        private List<String> mList = new ArrayList<>();
        private List<GroupDataBean> mDataList = new ArrayList<>();
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            final RecyclerView recyclerView;
            MyDbHelper myhelper = new MyDbHelper(this);
            db = myhelper.getWritableDatabase();
    
            cursor = db.rawQuery("select * from person", null);
            while (cursor.moveToNext()){
                GroupDataBean bean = new GroupDataBean();
                int id = cursor.getInt(0);
                String name = cursor.getString(1);
                String type = cursor.getString(cursor.getColumnIndex("type"));
                String imgurl = cursor.getString(cursor.getColumnIndex("imgurl"));
    
                bean.setTeam(name);
                bean.setArea(type);
                bean.setimageid(getimages(imgurl));
                mDataList.add(bean);
                this.result.append(name);
            }
            Log.d("test",this.result.toString()+cursor.getCount());
    
            recyclerView = (RecyclerView) findViewById(R.id.recycler_view_03);
            LinearLayoutManager manager = new LinearLayoutManager(getBaseContext(),LinearLayoutManager.VERTICAL,false);
            recyclerView.setLayoutManager(manager);
            GroupAdapter adapter = new GroupAdapter(mDataList);
            recyclerView.setAdapter(adapter);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    //                RelativeLayout reLayout =(RelativeLayout) findViewById(R.id.recycler_view_03);
    
                    final EditText nameV = (EditText)findViewById(R.id.name);
                    final EditText typeV = (EditText) findViewById(R.id.type);
                    final Button btnV = (Button) findViewById(R.id.button);
                    recyclerView.setVisibility(View.GONE);
                    nameV.setVisibility(View.VISIBLE);
                    typeV.setVisibility(View.VISIBLE);
                    btnV.setVisibility(View.VISIBLE);
                    //监听button事件
                    btnV.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            ContentValues values = new ContentValues();
                            values.put("name", String.valueOf(nameV.getText()));
                            values.put("type", String.valueOf(typeV.getText()));
                            values.put("imgurl", String.valueOf("l9"));
                            long rowid=db.insert("person", null, values);
                            if(rowid==-1)
                                Log.i("myDbDemo", "数据插入失败!");
                            else
                                Log.i("myDbDemo", "数据插入成功!"+rowid);
                            nameV.setVisibility(View.INVISIBLE);
                            typeV.setVisibility(View.INVISIBLE);
                            btnV.setVisibility(View.INVISIBLE);
                            mDataList.clear();
                            cursor = db.rawQuery("select * from person", null);
                            while (cursor.moveToNext()){
                                GroupDataBean bean = new GroupDataBean();
                                int id = cursor.getInt(0);
                                String name = cursor.getString(1);
                                String type = cursor.getString(cursor.getColumnIndex("type"));
                                String imgurl = cursor.getString(cursor.getColumnIndex("imgurl"));
    
                                bean.setTeam(name);
                                bean.setArea(type);
                                bean.setimageid(getimages(imgurl));
                                mDataList.add(bean);
                            }
    
                            LinearLayoutManager manager = new LinearLayoutManager(getBaseContext(),LinearLayoutManager.VERTICAL,false);
                            recyclerView.setLayoutManager(manager);
                            GroupAdapter adapter = new GroupAdapter(mDataList);
                            recyclerView.setAdapter(adapter);
                            recyclerView.setVisibility(View.VISIBLE);
    //                        Toast tot = Toast.makeText(
    //                                MainActivity.this,
    //                                "匿名内部类实现button点击事件",
    //                                Toast.LENGTH_LONG);
    //                        tot.show();
                        }
                    });
    //                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
    //                        .setAction("Action", null).show();
                }
            });
        }
    
        public static int getimages(String name){
            Class drawable = R.drawable.class;
            Field field = null;
            try {
                field =drawable.getField(name);
                int images = field.getInt(field.getName());
                return images;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return 0;
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
    
            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }
    
            return super.onOptionsItemSelected(item);
        }
    }
    
    

    出现过的问题

    DbHelper的Oncreate的时机没有把握清除

    由于时机把握错误,在第一次建库后就不会再执行Oncreat的插值。
    解决:换个数据库名,或者删除数据库。
    在这里插入图片描述

    没有Device File Manage

    这个安卓版本没有这个,但有Android Device Monitor可供资源文件的查找。
    在这里插入图片描述

    通过SQL查询的资源字符串得到其ID
    public static int getimages(String name){
    	Class drawable = R.drawable.class;
    	Field field = null;
    	try {
    		field =drawable.getField(name);
    		int images = field.getInt(field.getName());
    		return images;
    	} catch (Exception e) {
    		e.printStackTrace();
    	}
    	return 0;
    }
    
    
    Gradle更新导入design包出错

    原有的项目更新包失败。
    打算重新下一个Android Studio,目前采用的是重新建了一个项目,没有在原有的项目情况下继续添加悬浮按钮。
    在这里插入图片描述在这里插入图片描述

    执行结果截图

    通过GroupList展示通讯录的用户列表。
    在这里插入图片描述
    点击按钮,列表隐藏,输入框显示,可添加用户。
    在这里插入图片描述
    点击按钮insert执行并且列表重新加载(clear)。(列表显示、输入框隐藏)
    在这里插入图片描述

    待改进

    头像的上传功能并没有实现,对于新增加的用户,用的相同的资源名称。

    展开全文
  • 安卓手机通讯录

    2013-03-13 15:55:54
    安卓通讯录 所有功能都能实现
  • 安卓系统通讯录

    2012-10-15 22:18:19
    在移动通讯中实现的通讯录功能,例如android中实现通讯录得功能
  • 安卓qq通讯录

    2014-05-19 16:19:50
    qq通讯录安卓版,仿qq最新版的,功能实现了,可以拿去按自己的要求修改
  • 设计安卓手机通讯录 实现联系人增删查改,打电话,发短信功能
  • 安卓手机通讯录.zip

    2020-01-04 21:49:20
    手机通讯录是现代安卓手机里面最基本的功能,而且是安卓APP开发的一个经典案例,对于学习巩固Android应用技术有很大的帮助。对于当代智能手机,至少应该具备的的一项功能就是要能够存取联系人,并进行拨打电话,发送...
  • 安卓通讯录

    2014-09-18 10:36:20
    Delphi XE6实现安卓通讯录,采用最新XE7皮肤,还带留言板功能~ 拨打电话,发送短信
  • 仿手机通讯录功能实现代码.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 使用学习的HybridApp技术,编写一个跨平台的手机通讯录,可以访问查看本地的通讯录信息,实现常用的增加/删除/修改联系人功能,既可以在Android平台下运行,又可以在IOS平台下运行,并具有统一友好的用户界面。
  • android通讯录功能,实现了如下功能 1.检索手机存入联系人并显示 2.右侧导航条根据拼音字母检索联系人 3.通过搜索栏实时搜索联系人 4.vCard格式导出并发送分享功能 5.检测系统通讯录是否有变化,有变化在通知栏通知,并...
  • 安卓通讯录源码完整版,功能有导入系统联系人,实现联系人的增删改查,拨打电话,发短信等功能!!
  • 我想做简单点 每一行显示姓名和电话 但是需要点击它之后提示 删除 修改 操作 用哪个适配器合适呢? 联系人信息我是调的服务器接口! 谁有类似功能的源代码吗? 复杂的我目前还看不懂, 谢谢!
  • SIM卡运营商(获取手机号码功能暂时无法实现).zip,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 智能手机特别是安卓手机,功能越来越强大在人们的生活中应用越来越广泛,随之产生的通讯录管理系统也相继出现,现有的手机通讯录有添加,删除,修改联系人等功能, 为了能更加快速 准确的查询出用户所要搜索的内容, ...

    智能手机特别是安卓手机,功能越来越强大在人们的生活中应用越来越广泛,随之产生的通讯录管理系统也相继出现,现有的手机通讯录有添加,删除,修改联系人等功能, 为了能更加快速 准确的查询出用户所要搜索的内容, 再根据通讯录管理程序所应具有的功能, 本文模拟了手机管理系统的添加,删除,显示,查找,修改等功能,完成了手机通讯录的基本功能,本文主要使用switch语句,和封装函数,并且每一个功能都是一个模块,并在此基础上提 出了便捷的设计方案, 通过设计和开发该管理系统的实践,阐述了手机通讯录应具有的功能,并设计与实现.

    #include<iostream>
    using namespace std;
    #include<string>
    #define max  1000
        //设计联系人结构体
    struct person
    {
    	//姓名
    	string m_name;
    	//性别  1男  2女
    	int m_sex;
    
    	//年龄
    	int m_age;
        //电话
    	string m_phone;
    	//住址
    	string m_address;
    };
    //通讯录的结构体
    struct addressbooks
    {
    	//通讯录中保持的联系人数组
    	struct person personarray[max];
    	//通讯录中当前记录联系人个数
    	int m_size;
    	};
    //1.添加联系人
    void addperson(addressbooks*abs)
    {
    	//判断是否已满,如果满了就不在添加
    	if (abs->m_size == max)
    	{
    		cout << "通讯录已满,无法添加" << endl;
    		return;
    	}
    	else
    	{
    		//添加具体联系人
    
    		//姓名
    		string name;
    		cout << "请输入姓名:" << endl;
    		cin >> name;
    		abs->personarray[abs->m_size].m_name = name;
    
    			//性别
    		cout << "请输入性别" << endl;
    		cout << " 1---男" << endl;
    		cout << "2----女" << endl;
    		int sex = 0;
    		while (true)
    		{ 
    			cin >> sex;
    			if (sex == 1 || sex == 2)
    			{
    				abs->personarray[abs->m_size].m_sex = sex;
    				break;
    
    			}
    			cout << "输入有误,请重新输入" << endl;
    		   }
    		
    			//年龄
    		cout << "请输入年龄:" << endl;
    		int age = 0;
    		cin >> age;
    		abs->personarray[abs->m_size].m_age = age;
    
    			//电话
    		cout << "请输入联系电话:" << endl;
    		string phone;
    		cin >> phone;
    		abs->personarray[abs->m_size].m_phone = phone;
    		//住址
    		cout << "请输入家庭住址:" << endl;
    		string address;
    		cin >> address;
    		abs->personarray[abs->m_size].m_address = address;
    		//更新通讯录中人数
    		abs->m_size++;
    		cout << "添加成功" << endl;
    		system("pause");//请按任意键继续
    		system("cls");//清屏操作
    
    
    	}
    }
    
    //2.显示联系人
    void showperson(addressbooks*abs)
    {
    	//判断通讯录中人数是否为0.如果为0,提示记录为空
    	//如果不为0,显示联系人信息
    	if (abs->m_size == 0)
    	{
    		cout << "当前记录为空" << endl;
    	}
    	else
    	{
    		for (int i = 0; i < abs->m_size; i++)
    		{
    			cout << "姓名:" << abs->personarray[i].m_name <<"\t";
    			cout << "性别:" << (abs->personarray[i].m_sex==1 ? "男" : "女")<< "\t";
    			cout << "年龄:" << abs->personarray[i].m_age << "\t";
    			cout << "电话:" << abs->personarray[i].m_phone << "\t";
    			cout << "住址:" << abs->personarray[i].m_address << endl;
    		}
    	}
    	system("pause");//请按任意键继续
    	system("cls");//清屏操作
    }
    //3.删除联系人
    //检测联系人是否存在,如果存在,返回联系人所在数组中的具体位置,不存在返回-1
    int isexist(addressbooks*abs, string name)
    {
    	for (int i = 0; i < abs->m_size; i++)
    	{
    		//找到用户输入的姓名了
    		if (abs->personarray[i].m_name == name)
    		{
    			return i;//找到了,返回这个人在数组中的下标编号
    		}
    }
    	return -1;//如果遍历结束都没有找到,返回-1
    }
    void deleteperson(addressbooks*abs)
    {
    	cout << "请输入你要删除的联系人" << endl;
    	string name;
    	cin >> name;
    	//ret=-1 未查到
    	//ret!=-1 查到了
    	int ret = isexist(abs,name);
    	if (ret != -1)
    	{
    		//查到了,进行删除操作
    		for (int i = ret; i < abs->m_size; i++)
    		{
    			//数据前移
    			abs->personarray[i] = abs->personarray[i + 1];
    		}
    		abs->m_size--;//更新通讯录的人员数
    		cout << "删除成功" << endl;
    
    	}
    	else
    	{
    		cout << "查无此人" << endl;
    	}
    	system("pause");//请按任意键继续
    	system("cls");//清屏操作
    
    
    }
    //4.查找联系人
    void findperson(addressbooks*abs)
    {
    	cout << "请输入你要查找的联系人" << endl;
    	string name;
    	cin >> name;
    	//判断指定联系人是否存在通讯录中
    	int ret = isexist(abs, name);
    	if (ret != -1)//找到联系人
    	{
    		cout << "姓名" << abs->personarray[ret].m_name << "\t";
    		cout << "性别" << abs->personarray[ret].m_sex << "\t";
    		cout << "年龄" << abs->personarray[ret].m_age << "\t";
    		cout << "电话" << abs->personarray[ret].m_phone << "\t";
    		cout << "住址" << abs->personarray[ret].m_address << endl;
    
    	}
    	else//没有找到联系人
    	{
    		cout << "查无此人" << endl;
    	}
    	system("pause");//请按任意键继续
    	system("cls");//清屏操作
    
    }
    //5.修改联系人
    void modifyperson(addressbooks*abs)
    {
    	cout << "请输入你要修改的联系人" << endl;
    	string name;
    	cin >> name;
    	int ret = isexist(abs, name);
    	if (ret != -1)//找到联系人
    	{
    		//姓名
    		string name;
    		cout << "请输入姓名" << endl;
    		cin >> name;
    		abs->personarray[ret].m_name = name;
    		//性别
    		cout << "请输入性别" << endl;
    		cout << "1---男" << endl;
    		cout << "2---女" << endl;
    		int sex = 0;
    
    		while(true)
    		{
    			cin >> sex;
    			if (sex == 1 || sex == 2)
    			{
    				//输入正确,退出循环输入
    				abs->personarray[ret].m_sex = sex;
    				break;
    
    			}
    			cout << "输入有误,请重新输入" << endl;
    		}
    		//年龄
    		cout << "请输入年龄" << endl;
    		int age = 0;
    		cin >> age;
    		abs->personarray[ret].m_age = age;
    		//电话
    		cout << "请输入电话" << endl;
    		string phone;
    		cin >> phone;
    		abs->personarray[ret].m_phone = phone;
    		//住址
    		cout << "请输入一个家庭住址" << endl;
    		string address;
    		cin >> address;
    		abs->personarray[ret].m_address = address;
    		cout << "修改成功" << endl;
    
    	}
    	else//未找到联系人
    	{
    		cout << "查无此人" << endl;
    	}
    	system("pause");//请按任意键继续
    	system("cls");//清屏操作
    }
    //6.清空联系人
    void cleanperson(addressbooks*abs)
    {
    	abs->m_size = 0;
    	cout << "通讯录已空" << endl;
    	system("pause");//请按任意键继续
    	system("cls");//清屏操作
    
    }
    //菜单界面
    void showMenu()
    
    {
    	cout << "**************************"<<endl;
    	cout << "*****1.添加联系人*****" << endl;
    	cout << "*****2.显示联系人*****" << endl;
    	cout << "*****3.删除联系人*****" << endl;
    	cout << "*****4.查找联系人*****" << endl;
    	cout << "*****5.修改联系人*****" << endl;
    	cout << "*****6.清空联系人*****" << endl;
    	cout << "*****0.退出通讯录*****" << endl;
    	cout << "*************************" << endl;
      
    }
    
    int main()
    {
    //创建通讯录结构体变量
    	addressbooks abs;
    	//初始化通讯录当前个数
    	abs.m_size = 0;
    
    	int select = 0;//创建用户选择输入变量
    	while (true)
    	{
    		showMenu();//菜单调用
    		cin >> select;
    		switch (select)
    
    		{
    		case 1://添加联系人
    			addperson(&abs);//利用地址传递,可以修改实参
    			break;
    		case 2://显示联系人
    			showperson(&abs);
    			break;
    		case 3://删除联系人
    		{
    			cout << "请输入删除联系人姓名:" << endl;
    			string name;
    			cin>> name;
    			if (isexist(&abs, name) == -1)
    			{
    				cout << "查无此人" << endl;
    			}
    			else
    			{
    				cout << "找到此人" << endl;
    			}
    		}
    		deleteperson(&abs);
    			break;
    		case 4://查找联系人
    			findperson(&abs);
    			break;
    		case 5://修改联系人
    			modifyperson(&abs);
    			break;
    		case 6://清空联系人
    			cleanperson(&abs);
    			break;
    		case 0://退出通讯录
    			cout << "欢迎下次使用" << endl;
    			system("pause");
    			return 0;
    			break;
    
    
    		default:
    			break;
    		}
    	}
    	
    	system("pause");
    	return 0;
    
    }
    
    
    展开全文
  • 写完了发现我这通讯录实现了添加联系人,而没有重新编辑联系人信息和删除联系人的功能。。但我复习的目的已经达到了,所以这些功能就先忽略。 实现功能: 一、添加联系人; 二、点击联系人可以拨打对应号码; 界面...

    本人正处于安卓初步学习阶段,现整合一下知识点并写一个通讯录软件来实践一下。写完了发现我这通讯录只实现了添加联系人,而没有重新编辑联系人信息和删除联系人的功能。。但我复习的目的已经达到了,所以这些功能就先忽略。
    实现功能:
    一、添加联系人;
    二、点击联系人可以拨打对应号码;
    界面:
    一、主界面:
    在这里插入图片描述 主界面由一个自定义的标题栏控件和一个Listview组成。点下标题栏的添加按钮会启动AddActivity,显示添加联系人界面。ListView显示联系人列表,点击可拨打对应的号码。
    关键代码:
    `contactsView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override //为ListView注册监听
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
    name=contactsList.get(i);

                Cursor cursor1=db.query("Friend",null,"name=?",new String[]{name},null,null,null);
                if(cursor1.moveToFirst()){  number=cursor1.getString(cursor1.getColumnIndex("number"));
                    cursor1.close();}                            //取得点击项的number
                if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)!= PackageManager.PERMISSION_GRANTED)
                {
                    ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.CALL_PHONE},1);
    
                }
                else{call(number);}
            }
        });
    
    }
    private  void call(String number){
        //new一个对话框,ok里面实现打电话
        final String num=number;
        AlertDialog.Builder dialog=new AlertDialog.Builder(MainActivity.this);
        dialog.setTitle("");
        dialog.setMessage("打电话给"+name);
        dialog.setCancelable(true);
        dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
               try{ Intent intent=new Intent(Intent.ACTION_CALL);
                intent.setData(Uri.parse("tel:"+num));
                startActivity(intent);}catch(SecurityException e){
                   e.printStackTrace();
            }
    
            }
        });
     dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
         @Override
         public void onClick(DialogInterface dialogInterface, int i) {
    
         }
     });
     dialog.show();
    }`
    

    二、添加联系人界面在这里插入图片描述
    添加联系人界面如上图,输入名字和号码之后点击保存,将数据保存到SQLitebase。这里如果输入姓名或号码为空的话就用Toast提醒输入信息不完整。
    关键代码:

    saveButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    String name=editName.getText().toString();
                    String number=editNumber.getText().toString();
                    if(name.isEmpty()||number.isEmpty())
                    {
                        Toast.makeText(AddActivity.this,"输入信息不完整",Toast.LENGTH_SHORT).show();}
                   else {
                        SQLiteDatabase db=MainActivity.dbHelper.getWritableDatabase();
                        ContentValues values=new ContentValues();
                        values.put("name",name);
                        values.put("number",number);
                        db.insert("Friend",null,values);
                           //保存到数据库(用SQLiteDatabase)
                        MainActivity.contactsList.add(name);
                        MainActivity.adapter.notifyDataSetChanged();//名字更新listview
                        Toast.makeText(AddActivity.this,"联系人已保存",Toast.LENGTH_SHORT).show();
                       AddActivity.this.finish();
                    }
                }
            });
    

    演示:
    在这里插入图片描述
    涉及到的知识点:
    自定义控件顶部标题栏;
    各种系统控件;
    数据库SQLiteDatabase(保存联系人数据);
    运行时权限处理(拨打电话是危险权限需要做运行时权限处理)。

    展开全文
  • 我的原生APP目录借鉴的东西一,加药计算器加...实现不了自己需要的功能。 一个RadioGroup布局大框架,贯穿主活动MainActivity中,控件函数有点多。 一,加药计算器 目前,我写了两个项目: 1.加药计算器【工作使用中...
  • 简单的安卓拨号器源代码,可以实现拨号,查看,添加,联系人,发送短信.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。
  • 基于SQLite开发的简易通讯录 共两个页面:启动页+主页面 主页面实现增删改查、读取系统联系人、拨号等功能 非常非常非常简陋,所有功能都在主页面实现,没有封装类
  • 安卓开发实例,用初始化数据测试,实现功能,结构完整,代码无误
  • 通过 HBuilder X 下载 ColorUI,一款适应于H5、微信小程序、安卓、ios、支付宝的高颜值,高度自定义的Css组件库。页面部分方法来自ColorUI,例如侧边字母滑动。 正确路径引入vue-py.js 文件 百度网盘链接:vue-py ...
  • 我软件用Android写的,实现了本地联系人基本信息以及头像的读取,联系人头像的修改,联系人的增删改查功能实现,以及联系人的批量删除.zip,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行...
  • 通讯录简易版,带有基本增删改查,查询功能较完善,与现在手机的查询模式相当。服务器端使用my eclipse实现,客户端使用集成版eclipse实现,Android4.4
  • 这个在安卓可以实现三种功能,但是在苹果手机,只能实现拨打功能 <a style="color:#0096ff;" :href="'tel://'+item.mobile">{{item.mobile}}</a> 在vue组件内循环列表的时候,需要对href进行绑定并对...
  • Android通讯录的源代码

    热门讨论 2013-06-11 15:24:13
    基于java的安卓手机通讯录开发设计,安卓通讯录实现各种通讯录功能。代码很齐全,里面还有说明文档
  • 我在做简易通讯录实现这个功能 长按联系人显示删除 修改 两个功能
  • 安卓功能手机助手源码是一套基于安卓手机的多功能手机助手的项目源码,实现功能有手机软件的管理、硬件信息的读取显示、电量情况读取和显示、闹钟设置、相机、通讯录、联系人、短信的读取和显示。还可以一键结束...

空空如也

空空如也

1 2 3 4 5
收藏数 84
精华内容 33
关键字:

安卓实现通讯录功能