【Android联系人】仿小米联系人(MIUI8)

来源:互联网 发布:http网络协议 编辑:程序博客网 时间:2024/05/16 12:16

头一次写博客,文笔不好。

apk下载地址:https://www.pgyer.com/MiContacts

先上效果图:

这里写图片描述

既然是展示联系人信息,首先需要的是添加获取联系人权限:

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

主页面是自己写了一个滑动的tab+viewpager+fragment实现。接下来就是联系人页面,主要就以下几点:
①.获取系统联系人数据;
②.列表的滑动,头部字母悬浮;
③.右侧的索引栏;
④.文字图片的实现。

首先,分析布局,肯定需要用到列表,然后就是右侧的索引,还有就是点击索引时候出现的一个小提示。由于这方面网上有很多写好的,大家可以搜索一下。我这里用的是:

//字母索引compile 'com.bigkoo:quicksidebar:1.0.2'

接下来分析一下头部悬浮,做法有很多。说一个简单的,我们可以直接用listView的SectionIndexer来监听,滑动标题悬浮,然后再加上动画实现顶上去的效果。这里有一篇郭神的文章,里边说的很详细。有兴趣可以看一下:Android系统联系人全特效实现(上),分组导航和挤压动画
我呢,也直接用写好的,用recyclerview实现:

//recyclerview分组,顶部浮动compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar'

这样的话,基本上联系人页面的布局我们就可以直接写出来了:

<?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"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical">    <RelativeLayout        android:layout_width="match_parent"        android:layout_height="match_parent">        <android.support.v7.widget.RecyclerView            android:id="@+id/recyclerView"            android:layout_width="match_parent"            android:layout_height="match_parent" />        <com.bigkoo.quicksidebar.QuickSideBarTipsView            android:id="@+id/quickSideBarTipsView"            android:layout_width="@dimen/height_quicksidebartips"            android:layout_height="match_parent"            android:layout_toLeftOf="@+id/quickSideBarView"            app:sidebarBackgroundColor="@color/colorPrimary"            app:sidebarTextColor="@android:color/white"            app:sidebarTextSize="@dimen/textSize_quicksidebartips" />        <com.bigkoo.quicksidebar.QuickSideBarView            android:id="@id/quickSideBarView"            android:layout_width="20dp"            android:layout_height="match_parent"            android:layout_alignParentRight="true"            app:sidebarItemHeight="@dimen/height_quicksidebaritem"            app:sidebarTextColor="@android:color/black"            app:sidebarTextColorChoose="@color/colorPrimary"            app:sidebarTextSize="@dimen/textSize_quicksidebar"            app:sidebarTextSizeChoose="@dimen/textSize_quicksidebar_choose" />    </RelativeLayout></LinearLayout>

接下来就先撸代码吧。什么findViewby…..,这里介绍一个神器:Android Studio插件-自动根据布局生成Activity等代码(开源) 极大的提升效率。

获取系统联系人需要注意的是权限,在android6.0以上需要自己请求权限,这是跟6.0之前版本不同的地方。我就直接在onResume下面进行处理,然后做相应操作。

private static final int READ_CONTACTS_PERMISSIONS_REQUEST = 1;    private void checkPermission() {        //版本判断        if (Build.VERSION.SDK_INT >= 23) {            //减少是否拥有权限            int checkCallPhonePermission = ContextCompat.checkSelfPermission(getActivity(),                    Manifest.permission.READ_CONTACTS);            if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {                // Show our own UI to explain to the user why we need to read the contacts                // before actually requesting the permission and showing the default UI                ActivityCompat.requestPermissions(getActivity(),                        new String[]{Manifest.permission.READ_CONTACTS},READ_CONTACTS_PERMISSIONS_REQUEST);            }else{                initContants();            }        } else {            initContants();        }    }    @Override    public void onRequestPermissionsResult(int requestCode,                                           @NonNull String permissions[],                                           @NonNull int[] grantResults) {        // Make sure it's our original READ_CONTACTS request        if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) {            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {                initContants();                return;            } else {                Toast.makeText(getActivity(), "Read Contacts permission denied", Toast.LENGTH_SHORT).show();            }        } else {            super.onRequestPermissionsResult(requestCode, permissions, grantResults);        }    }

接下来,就是上边代码中看到initContants()方法了,这里边主要就是获取联系人的数据,然后给recyclerview绑定adapter。具体代码:

private void initContants() {        Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;        Cursor cursor = getActivity().getContentResolver().query(uri,                new String[]{"display_name", "sort_key"}, null, null, "sort_key");        if (cursor.moveToFirst()) {            do {                String name = cursor.getString(0);                String sortKey = getSortKey(cursor.getString(1));                Contacts contact = new Contacts();                contact.setName(name);                contact.setSortKey(sortKey);                contacts.add(contact);            } while (cursor.moveToNext());        }        getActivity().startManagingCursor(cursor);//cursor的生命周期托管给activity        //设置列表数据和浮动header        final LinearLayoutManager layoutManager = new                LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);        recyclerView.setLayoutManager(layoutManager);        // Add the sticky headers decoration        ContactsListWithHeadersAdapter adapter = new ContactsListWithHeadersAdapter();        ArrayList<String> customLetters = new ArrayList<>();        int position = 0;        for (Contacts contact : contacts) {            String letter = contact.getSortKey();            //如果没有这个key则加入并把位置也加入            if (!letters.containsKey(letter)) {                letters.put(letter, position);                customLetters.add(letter);            }            position++;        }        //不自定义则默认26个字母        quickSideBarView.setLetters(customLetters);        adapter.addAll(contacts);        recyclerView.setAdapter(adapter);        final StickyRecyclerHeadersDecoration headersDecor = new StickyRecyclerHeadersDecoration(adapter);        recyclerView.addItemDecoration(headersDecor);        // Add decoration for dividers between list items        recyclerView.addItemDecoration(new DividerDecoration(getActivity()));    }

还有一个部分就是汉字首字母的处理,这里直接用的是CharacterParser,网上很容易搜索到的。

接下来就是写适配器了,适配器的话主要有一个地方需要注意,就是圆形图片文字,在这里直接用的开源的CircleTextImageView,我们没必要自己写,嘿嘿。所以需要引入:

//圆形文字compile 'com.github.thinkcool:circletextimageview:1.0.20151218'

然后就是适配器的一些代码了:

private class ContactsListWithHeadersAdapter extends ContactsListAdapter<RecyclerView.ViewHolder>            implements StickyRecyclerHeadersAdapter<RecyclerView.ViewHolder> {        @Override        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            View view = LayoutInflater.from(parent.getContext())                    .inflate(R.layout.adapter_contacts_item, parent, false);            return new RecyclerView.ViewHolder(view) {            };        }        @Override        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {            View itemView = holder.itemView;            TextView mName = (TextView) itemView.findViewById(R.id.mName);            CircleTextImageView mUserPhoto = (CircleTextImageView) itemView.findViewById(R.id.mUserPhoto);            LinearLayout mBottomLayout=(LinearLayout)itemView.findViewById(R.id.mBottomLayout);            if (position<contacts.size()-1){                if (getItem(position).getSortKey().equals(getItem(position+1).getSortKey())){                    mBottomLayout.setVisibility(View.GONE);                }else {                    mBottomLayout.setVisibility(View.VISIBLE);                }            }else {                mBottomLayout.setVisibility(View.GONE);            }            String name = getItem(position).getName();            mName.setText(name);            if (name.substring(name.length() - 1).equals("(") ||                    name.substring(name.length() - 1).equals(")") ||                    name.substring(name.length() - 1).equals("[") ||                    name.substring(name.length() - 1).equals("]")||                    name.substring(name.length() - 1).equals("(") ||                    name.substring(name.length() - 1).equals(")") ||                    name.substring(name.length() - 1).equals("【") ||                    name.substring(name.length() - 1).equals("】")) {                mUserPhoto.setText(name.substring(name.length() - 2,name.length() - 1));            } else {                mUserPhoto.setText(name.substring(name.length() - 1));            }        }        @Override        public long getHeaderId(int position) {            return getItem(position).getSortKey().charAt(0);        }        @Override        public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {            View view = LayoutInflater.from(parent.getContext())                    .inflate(R.layout.adapter_contacts_head, parent, false);            return new RecyclerView.ViewHolder(view) {            };        }        @Override        public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int position) {            View itemView = holder.itemView;            TextView mHead = (TextView) itemView.findViewById(R.id.mHead);            mHead.setText(String.valueOf(getItem(position).getSortKey()));//            holder.itemView.setBackgroundColor(getRandomColor());        }        private int getRandomColor() {            SecureRandom rgen = new SecureRandom();            return Color.HSVToColor(150, new float[]{                    rgen.nextInt(359), 1, 1            });        }    }

头一次写博客,文笔不好,请见谅。
希望我的文章对你有帮助,有什么问题请留言。

附上源代码:https://github.com/NewsChen/MiContacts

0 0
原创粉丝点击