精华内容
下载资源
问答
  • Android仿微信通讯录

    千次阅读 2019-09-24 10:06:08
    Android仿微信通讯录 分3部: 1、listview实现显示头像、名字(太简单,这里就不写了) 通讯录页面xml布局代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:...

    Android仿微信通讯录

     

    分3部:

    1、listview实现显示头像、名字(太简单,这里就不写了)

    通讯录页面xml布局代码:

    <LinearLayout 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"
       >
    
        <FrameLayout
            android:id="@+id/fl"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
    
    
            <ListView
    
                android:id="@+id/school_friend_member"
    
                android:layout_width="match_parent"
    
                android:layout_height="match_parent"
    
                android:cacheColorHint="@android:color/transparent"
    
                android:dividerHeight="1px"
    
                android:fadingEdge="none"
    
                android:listSelector="@android:color/transparent"
    
                android:scrollbars="none"></ListView>
    
    
            <TextView
    
                android:id="@+id/school_friend_dialog"
    
                android:layout_width="80dp"
    
                android:layout_height="80dp"
    
                android:layout_gravity="center"
    
                android:background="@color/green_light"
    
                android:gravity="center"
    
                android:textColor="#ffffffff"
    
                android:textSize="30dp"
    
                android:visibility="invisible" />
    
    
            <com.diancanwang.dell.diancanwang.chat.bean.SideBar
    
                android:id="@+id/school_friend_sidrbar"
    
                android:layout_width="30dp"
    
                android:layout_height="match_parent"
    
                android:layout_gravity="right|center" />
    
        </FrameLayout>
    
    </LinearLayout>

    2、实现A——Z的好友分类

    首先 导入拼音依赖

    compile files('libs/pinyin4j-2.5.0.jar')  (依赖可以到网上搜索一个,添加到app下面的libs文件夹里,我这里给出的是我添加好后app build.gradle里面的)

    其次

    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.HanyuPinyinVCharType;
    import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
    
    import java.util.Comparator;
    
    /**
     * 2018/4/22.
     */
    
    public class PinyinComparator implements Comparator<SortModel> {
        public int compare(SortModel o1, SortModel o2) {
            if (o1.getSortLetters().equals("@")
                    || o2.getSortLetters().equals("#")) {
                return -1;
            } else if (o1.getSortLetters().equals("#")
                    || o2.getSortLetters().equals("@")) {
                return 1;
            } else {
                return o1.getSortLetters().compareTo(o2.getSortLetters());
            }
        }
    
        public static String getPingYin(String inputString) {
            HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
            format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
            format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
            format.setVCharType(HanyuPinyinVCharType.WITH_V);
            char[] input = inputString.trim().toCharArray();
            String output = "";
            try {
                for (char curchar : input) {
                    if (java.lang.Character.toString(curchar).matches("[\u4e00-\u9fa5]+")) {
                        String[] temp = PinyinHelper.toHanyuPinyinStringArray(curchar, format);
                        output += temp[0];
                    } else
                        output += java.lang.Character.toString(curchar);
                }
            } catch (BadHanyuPinyinOutputFormatCombination e) {
                e.printStackTrace();
            }
            return output;
        }
    
    }

     

    实体类

    /**
     *  2018/4/22.
     * 实体类
     */
    
    public class SortModel {
        private int img;//头像
        private String name;   //显示的数据
        private String sortLetters;  //显示数据拼音的首字母
    
        public SortModel(int img, String name, String sortLetters) {
            this.img = img;
            this.name = name;
            this.sortLetters = sortLetters;
        }
    
        public SortModel() {
        }
    
        public int getImg() {
            return img;
        }
    
        public void setImg(int img) {
            this.img = img;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getSortLetters() {
            return sortLetters;
        }
    
        public void setSortLetters(String sortLetters) {
            this.sortLetters = sortLetters;
        }
    
        @Override
        public String toString() {
            return "SortModel{" +
                    "img=" + img +
                    ", name='" + name + '\'' +
                    ", sortLetters='" + sortLetters + '\'' +
                    '}';
        }
    }

     

    
    import android.widget.ListView;
    import android.widget.TextView;
    
    import com.diancanwang.dell.diancanwang.R;
    import com.diancanwang.dell.diancanwang.base.BaseFragment;
    import com.diancanwang.dell.diancanwang.chat.adapter.SortAdapter;
    import com.diancanwang.dell.diancanwang.chat.bean.PinyinComparator;
    import com.diancanwang.dell.diancanwang.chat.bean.SideBar;
    import com.diancanwang.dell.diancanwang.chat.bean.SortModel;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import butterknife.Bind;
    
    /**
     * 通讯录页面
     */
    public class AddBookFragment extends BaseFragment {
    
        @Bind(R.id.school_friend_member)
        ListView mListView;
        @Bind(R.id.school_friend_dialog)
        TextView mDialog;
        @Bind(R.id.school_friend_sidrbar)
        SideBar mSideBar;
        private List<SortModel> list;
    
        @Override
        protected int getLayoutId() {
            return R.layout.fragment_add_book;
        }
    
        @Override
        protected void initView() {
    
        }
    
        @Override
        protected void initData() {
            list = new ArrayList<>();
    //        for (int i = 0; i < 10; i++) {
            SortModel sortModel = new SortModel();
            SortModel sortModel1 = new SortModel();
            SortModel sortModel2 = new SortModel();
            SortModel sortModel3 = new SortModel();
            SortModel sortModel4 = new SortModel();
            SortModel sortModel5 = new SortModel();
    
    
            sortModel.setImg(R.mipmap.ic_launcher);
            sortModel1.setImg(R.mipmap.ic_launcher);
            sortModel2.setImg(R.mipmap.ic_launcher);
            sortModel3.setImg(R.mipmap.ic_launcher);
            sortModel4.setImg(R.mipmap.ic_launcher);
            sortModel5.setImg(R.mipmap.ic_launcher);
            sortModel2.setName("华为");
            sortModel.setName("阿里巴巴");
            sortModel1.setName("百度");
            sortModel3.setName("xiaoxue");
            sortModel4.setName("……%¥#¥%#");
            sortModel5.setName("百家姓");
    
            String pingYin = PinyinComparator.getPingYin("阿里巴巴");
            String pingYin1 = PinyinComparator.getPingYin("百度");
            String pingYin2 = PinyinComparator.getPingYin("华为");
            String pingYin3 = PinyinComparator.getPingYin("xiaoxue");
            String pingYin4 = PinyinComparator.getPingYin("……%¥#¥%#");
            String pingYin5 = PinyinComparator.getPingYin("百家姓");
    
            sortModel3.setSortLetters(pingYin3);
            sortModel.setSortLetters(pingYin);
            sortModel1.setSortLetters(pingYin1);
            sortModel2.setSortLetters(pingYin2);
            sortModel4.setSortLetters(pingYin4);
            sortModel5.setSortLetters(pingYin5);
    
    
    
            list.add(sortModel2);
            list.add(sortModel1);
            list.add(sortModel3);
            list.add(sortModel);
            list.add(sortModel4);
            list.add(sortModel5);
    
    //        }
        }
    
        @Override
        protected void initAdapter() {
            SortAdapter adapter = new SortAdapter(list, getActivity());
            mListView.setAdapter(adapter);
        }
    
    
    }

     

    适配器

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.SectionIndexer;
    import android.widget.TextView;
    
    import com.bumptech.glide.Glide;
    import com.diancanwang.dell.diancanwang.R;
    import com.diancanwang.dell.diancanwang.chat.bean.PinyinComparator;
    import com.diancanwang.dell.diancanwang.chat.bean.SortModel;
    
    import java.util.Collections;
    import java.util.List;
    
    /**
     * 2018/4/22.
     */
    
    public class SortAdapter extends BaseAdapter implements SectionIndexer {
        private List<SortModel> list;
        private Context mContext;
    
        public SortAdapter(List<SortModel> list, Context mContext) {
            this.list = list;
            this.mContext = mContext;
        }
    
        public void updateListView(List<SortModel> list) {
            this.list = list;
            notifyDataSetChanged();
        }
    
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder = null;
            if (convertView == null) {
                viewHolder = new ViewHolder();
                convertView = LayoutInflater.from(mContext).inflate(R.layout.item, null);
                //头像
                viewHolder.imgHead = (ImageView) convertView.findViewById(R.id.book_head);
                //昵称
                viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.book_name);
                //索引字母
                viewHolder.tvLetter = (TextView) convertView.findViewById(R.id.catalog);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
    
    
             获取首字母的assii值
            int section = getSectionForPosition(position);
            //通过首字母的assii值来判断是否显示字母
            int positionForSelection = getPositionForSection(section);
    
            viewHolder.tvLetter.setOnClickListener(null);
    
            if (position == positionForSelection) {
    
                viewHolder.tvLetter.setVisibility(View.VISIBLE);
                //把拼音转成大写字母,并取首字母    toUpperCase()  转换为大写字母
                String firstLetter = list.get(position).getSortLetters().substring(0, 1).toUpperCase();
                // 正则表达式,判断首字母是否是英文字母
                if (firstLetter.matches("[A-Z]")) {
    //              给通讯录好友排序(按照从A-Z的顺序)
                    Collections.sort(list, new PinyinComparator());
                    //给控件设置值
                    viewHolder.tvLetter.setText(firstLetter);
                } else {
                    viewHolder.tvLetter.setText("#");
                }
    
    
            } else {
                viewHolder.tvLetter.setVisibility(View.GONE);
            }
    
            Glide.with(mContext).load(list.get(position).getImg()).into(viewHolder.imgHead);
            viewHolder.tvTitle.setText(list.get(position).getName());
    
            return convertView;
        }
    
        final static class ViewHolder {
            ImageView imgHead;
            TextView tvLetter;
            TextView tvTitle;
        }
    
        @Override
        public Object[] getSections() {
            return null;
        }
    
        @Override
        public int getPositionForSection(int section) {
            for (int i = 0; i < getCount(); i++) {
                String sortStr = list.get(i).getSortLetters();
                char firstChar = sortStr.toUpperCase().charAt(0);
                if (firstChar == section) {
                    return i;
                }
            }
    
            return -1;
    
        }
    
        @Override
        public int getSectionForPosition(int position) {
    
            return list.get(position).getSortLetters().toUpperCase().charAt(0);
        }
    }

    适配器里的xml布局

    <?xml version="1.0" encoding="utf-8"?>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="vertical">
    
    
        <TextView
            android:id="@+id/catalog"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#F9F9F9"
            android:paddingBottom="5dp"
            android:paddingLeft="20dp"
            android:paddingTop="5dp"
            android:text="A"
            android:textColor="#454545" />
    
    <!--
    
        <TextView
    
            android:id="@+id/line"
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:background="@color/green_light" />
    -->
    
    
        <LinearLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:background="@color/white"
            android:orientation="horizontal"
            android:paddingBottom="5dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="5dp">
    
    
            <ImageView
                android:id="@+id/book_head"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:src="@color/green_light" />
    
    
            <TextView
                android:id="@+id/book_name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dip"
                android:ellipsize="end"
                android:gravity="center_vertical"
                android:singleLine="true"
                android:text="xxxx"
                android:textColor="#323232"
                android:textSize="16sp" />
    
        </LinearLayout>
    
    
    </LinearLayout>

    3.实现右侧的字母导航

    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.drawable.ColorDrawable;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.widget.TextView;
    
    /**
     *  2018/4/16.
     * 侧边栏 SideBar
     */
    
    public class SideBar extends View {
    
        //触摸事件(用的接口回调)
        private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
    
        //26个字母
        public static String[] b = {"A", "B", "C", "D", "E", "F", "G", "H", "I",
                "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
                "W", "X", "Y", "Z", "#"};
    
    
        private int choose = -1;// 选中
        private TextView mTextDialog;
    
        public void setTextView(TextView mTextDialog) {
            this.mTextDialog = mTextDialog;
        }
    
        public SideBar(Context context) {
            super(context);
        }
    
        public SideBar(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            Paint paint = new Paint();
            int height = getHeight();//获取高度
            int width = getWidth();//获取宽度
            int singleHeight = height / b.length;//获取每一个字母的高度
    
            for (int i = 0; i < b.length; i++) {
                paint.setColor(Color.parseColor("#838383"));//未选中的颜色
                paint.setTextSize(30);
                paint.setAntiAlias(true);//抗锯齿功能
                // 选中的状态
                if (i == choose) {
                    paint.setColor(Color.BLACK);//选中的颜色
                    paint.setFakeBoldText(false); //true为粗体,false为非粗体            }
                }
                // x坐标等于中间-字符串宽度的一半.
                float xPos = width / 2 - paint.measureText(b[i]) / 2;
                float yPos = singleHeight * i + singleHeight;
                canvas.drawText(b[i], xPos, yPos, paint);
                paint.reset();// 重置画笔
    
    
            }
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            final int action = event.getAction();
            final float y = event.getY();// 点击y坐标
            final int oldChoose = choose;
            final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
            final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
    
            switch (action) {
                case MotionEvent.ACTION_UP:
                    setBackgroundDrawable(new ColorDrawable(0x00000000));
                    choose = -1;//
                    invalidate();
                    if (mTextDialog != null) {
                        mTextDialog.setVisibility(View.INVISIBLE);
                    }
    
                    break;
    
                default:
                    setBackgroundColor(Color.TRANSPARENT);
                    if (oldChoose != c) {  //判断选中字母是否发生改变
                        if (c >= 0 && c < b.length) {
                            if (listener != null) {
                                listener.onTouchingLetterChangedListener(b[c]);
                            }
                            if (mTextDialog != null) {
                                mTextDialog.setText(b[c]);
                                mTextDialog.setVisibility(View.VISIBLE);
                            }
    
                            choose = c;
                            invalidate();
                        }
                    }
    
                    break;
            }
    
            return true;
        }
    
        public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
            this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
        }
    
        public interface OnTouchingLetterChangedListener {
            void onTouchingLetterChangedListener(String s);
        }
    }
    

    在设置数据的页面把SideBar和Dialog绑定再一起,然后初始化监听

      protected void initView() {
    //        把SideBar和Dialog绑定
            mSideBar.setTextView(mDialog);
    
    
            mSideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {
                @Override
                public void onTouchingLetterChangedListener(String s) {
    
                    // 该字母首次出现的位置
                    int position = adapter.getPositionForSection(s.charAt(0));
                    if (position != -1) {
                        mListView.setSelection(position);
                    }
    
                }
            });
        }
    展开全文
  • 主要为大家详细介绍了Android仿微信通讯录列表侧边栏效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要介绍了Android仿微信通讯录滑动快速定位功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • Android仿微信通讯录侧边栏
  • 主要介绍了Android 仿微信通讯录导航分组列表,使用ItemDecoration为RecyclerView打造带悬停头部的分组列表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 本篇文章主要介绍了android仿微信通讯录搜索示例(匹配拼音,字母,索引位置),具有一定的参考价值,有兴趣的可以了解一下
  • 模仿了一下微信的联系人界面UI,由于是新手,所以看起来很简单的界面,结果被搞得半死,弄到凌晨5点,实在吃不消了,就睡了,早上9点又有...先来一张原版的微信通讯录截图 对,界面就是这样的,很熟悉的界面吧,下面就

    模仿了一下微信的联系人界面UI,由于是新手,所以看起来很简单的界面,结果被搞得半死,弄到凌晨5点,实在吃不消了,就睡了,早上9点又有小伙伴过来找我,约好了下午出去爬山的,没睡醒就出去玩了,一下午头都很痛,整个人也很晕,简直日了狗。。。不过还好,现在回来了,就迫不及待打开电脑写博客了,怕以后会忘。好了,废话不多说,开始切入正题!

    先来一张原版的微信通讯录截图

    对,界面就是这样的,很熟悉的界面吧,下面就开始写我是如何模仿的,先贴一下我的成果图


    我只是模仿了一个大概,界面很简单,顶部是一个搜索框,然后下面是一个ListView用来显示好友列表,最右边有一排英文字母,用来快速定位的,我就不多做介绍了,这种功能如果还不清楚的话,就打开手机微信自己感受一下吧

    1.自定义View-屏幕最右边的一排英文字母

    public class LetterView extends View {
    
        private OnTouchingLetterChangedListener mOnTouchingLetterChangedListener;
        private String[] letters = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
                "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#" };
        private TextView tv;
    
        public void setTextView(TextView tv) {
            this.tv = tv;
        }
    
        public LetterView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public LetterView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public LetterView(Context context) {
            super(context);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            // 每一个字母的高度
            int letter_height = getHeight() / letters.length;
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setDither(true);
            paint.setColor(Color.BLACK);
            paint.setTypeface(Typeface.DEFAULT_BOLD);
            paint.setTextAlign(Align.CENTER);
            paint.setTextSize(Math.min(getWidth(), getHeight() / 27) - 2);
            // drawText方法可以把26个英文字母画到控件上
            for (int i = 0, current_height = 0; i < 27; i++) {
                current_height += letter_height;
                canvas.drawText(letters[i], getWidth() / 2, current_height, paint);
            }
        }
    
        /** 当手指在该控件上拖动的时候,字母会改变 **/
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                tv.setVisibility(View.INVISIBLE);
                break;
            default:
                float y = event.getY();
                int position = (int) (y / (getHeight() / 27));
                if (position < 27 && position >= 0) {
                    tv.setText(letters[position]);
                    tv.setVisibility(View.VISIBLE);
                    mOnTouchingLetterChangedListener.onTouchingLetterChanged(letters[position].charAt(0));
                } else {
                    tv.setVisibility(View.INVISIBLE);
                }
                break;
            }
            return true;
        }
    
        public void setOntouchingLetterChangedListener(OnTouchingLetterChangedListener mtOnTouchingLetterChangedListener) {
            this.mOnTouchingLetterChangedListener = mtOnTouchingLetterChangedListener;
        }
    
        /** 回调接口,手指的拖动,会导致英文字母的改变,并做出响应的处理 **/
        public interface OnTouchingLetterChangedListener {
            public void onTouchingLetterChanged(char c);
        }
    }

    2.顶部的搜索框
    搜索框的代码其实很好写,也就是一个EditText,但是需要监听输入状态,每次输入框的内容改变,我们都要进行一次数据的检索,提高用户体验,调用EditText的addTextChangedListener()方法就可以了,业务逻辑自己在里面写

    3.显示好友列表的ListView
    首先,我们从数据库取出来的好友列表并不一定是我们想要的顺序,所以我们需要先对好友列表进行排序,排序规则:按照首字母进行A~Z排序,如果首字母不是英文字母,是特殊符号或者数字活着其他乱七八糟的什么,那就归类到#,排序很简单,我的代码是这样的:

    Collections.sort(list, new Comparator<Friend>() {
    
                @Override
                public int compare(Friend o1, Friend o2) {
                    String c1 = o1.getFistChar() + "";
                    String c2 = o2.getFistChar() + "";
                    if (c1.equals("#")) {
                        return 1;
                    }
                    if (c2.equals("#")) {
                        return -1;
                    }
    
                    return c1.compareTo(c2);
                }
            });

    我已经提前用pinyin4j这个第三方库将每个好友的首字母提取出来了,这类文章网上很多,想知道如何使用的,自己去百度吧,我这里就不多讲了

    排序排好了,我们就开始配置adapter了,adapter是继承了BaseAdapter,我的每个item布局是这样的:

    再展示一下adapter里面的getView方法

    class ViewHolder {
            TextView key;
            TextView friend_name;
            ImageView friend_img;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            Friend friend = getItem(position);
            ViewHolder holder;
            if (convertView == null) {
                convertView = inflater.inflate(R.layout.friend_list_item, null);
                holder = new ViewHolder();
                holder.key = (TextView) convertView.findViewById(R.id.key);
                holder.friend_img = (ImageView) convertView.findViewById(R.id.friend_img);
                holder.friend_name = (TextView) convertView.findViewById(R.id.friend_name);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
    
            if (getPositionForSection(friend.getFistChar()) == position) {
                holder.key.setText(friend.getFistChar() + "");
                holder.key.setVisibility(View.VISIBLE);
            } else {
                holder.key.setVisibility(View.GONE);
            }
            holder.friend_name.setText(friend.getName());
            return convertView;
        }
    
        private int getPositionForSection(char c) {
            for (int i = 0; i < list.size(); i++) {
                if (getItem(i).getFistChar() == c) {
                    return i;
                }
            }
            return -1;
        }

    listview中的每个item都对应着一个联系人,判断该联系人的首字母是否是排在该类的第一个,如果是第一个,就显示首字母,如果不是第一个,就不显示首字母。举个例子,如果我有一个list,里面存放着一大堆联系人,并且已经排好顺序了,如{”阿猫”,”阿狗”,”壁虎”,”Big”,”白天黑夜”,”单身狗”,”淡淡的”,”的”,”冯”,”种子”},如果item要显示壁虎的信息,就需要首字母这个控件,如果item要显示Big的信息,就不需要显示首字母这个空间,因为壁虎和Big都属于B类,而且壁虎排在第一个,所以只要第一个显示首字母空间就可以了

    好了,这个项目差不多也完了,还有一个挤压的功能没有写出来,因为本人能力有限,等以后技术成熟了再来完善这篇博客吧

    展开全文
  • Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表,修改bug版本.zip 【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部...
  • Android 仿微信通讯录

    千次阅读 2018-08-09 17:37:55
    这篇写下常用的类似通讯录似得效果 右边自定义一个sidebar 左边使用listview实现 效果如下: 1、自定义SideBar  ①重写onDraw 计算每个字母所占的高度 就是整体的高度除以要画的字母的个数,所以每个字母的...

    这篇写下常用的类似通讯录似得效果    右边自定义一个sidebar  左边使用listview实现

    效果如下:

    1、自定义SideBar 

    ①重写onDraw     计算每个字母所占的高度  就是整体的高度除以要画的字母的个数,所以每个字母的高为依次叠加

    因为竖行排列,所以每个字母的宽都一样,每个字母的x为整体的宽度减去该字母的宽度的一半

    ②重写触摸事件  拿到触摸的y除以总的高度 然后乘以所有字母的个数  就可以拿到点击的是第几个字母,如果该字母改变则进行重绘

    ③设置回调  点击该字母具体方法由外界实现

    public class SideBar extends View {
        // 触摸事件
        private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
        // 26个字母
        public static String[] b = {"☆", "#", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W",
                "X", "Y", "Z"};
        //侧边栏字母大小
        private float size;
        private int choose = -1;// 选中
        private Paint paint = new Paint();
    
        private TextView mTextDialog;
    
        public void setTextView(TextView mTextDialog) {
            this.mTextDialog = mTextDialog;
        }
    
        public SideBar(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(context);
        }
    
        public SideBar(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public SideBar(Context context) {
            super(context);
            init(context);
        }
    
        private void init(Context context) {
            size = DeviceUtil.dip2px(context, 13);
        }
    
        /**
         * 重写这个方法
         */
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 获取焦点改变背景颜色.
            int height = getHeight();// 获取对应高度
            int width = getWidth(); // 获取对应宽度
            int singleHeight = height / b.length;// 获取每一个字母的高度
    
            for (int i = 0; i < b.length; i++) {
                if (!isInEditMode()) {
                    paint.setColor(Color.parseColor("#838383"));
                }
                //设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。
                paint.setAntiAlias(true);
                paint.setTextSize(size);
                // 选中的状态
                if (i == choose) {
                    paint.setColor(getResources().getColor(R.color.yellow_light));
                    paint.setFakeBoldText(true); //true为粗体,false为非粗体
                }
                // x坐标等于中间-字符串宽度的一半.
                float xPos = width / 2 - paint.measureText(b[i]) / 2;
                float yPos = singleHeight * i + singleHeight;
                canvas.drawText(b[i], xPos, yPos, paint);
                paint.reset();// 重置画笔
            }
    
        }
    
        @SuppressWarnings("deprecation")
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            final int action = event.getAction();
            final float y = event.getY();// 点击y坐标
            final int oldChoose = choose;
            final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
            final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
    
            switch (action) {
                case MotionEvent.ACTION_UP:
                    setBackgroundDrawable(new ColorDrawable(0x00000000));
                    choose = -1;//
                    invalidate();
                    if (mTextDialog != null) {
                        mTextDialog.setVisibility(View.INVISIBLE);
                    }
                    break;
    
                default:
                    if (oldChoose != c) {
                        if (c >= 0 && c < b.length) {
                            if (listener != null) {
                                listener.onTouchingLetterChanged(b[c]);
                            }
                            if (mTextDialog != null) {
                                mTextDialog.setText(b[c]);
                                mTextDialog.setVisibility(View.VISIBLE);
                            }
    
                            choose = c;
                            invalidate();
                        }
                    }
    
                    break;
            }
            return true;
        }
    
        /**
         * 向外公开的方法
         *
         * @param onTouchingLetterChangedListener
         */
        public void setOnTouchingLetterChangedListener(OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
            this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
        }
    
        /**
         * 接口
         *
         * @author coder
         */
        public interface OnTouchingLetterChangedListener {
            public void onTouchingLetterChanged(String s);
        }
    
    }

    2、准备好汉字转拼音的工具类

      ①将jar包丢到libs目录下

         

      ②  汉字转拼音工具类

    public class PinYinUtil {
        /**
         * 获取汉字的拼音
         * @param chinese
         * @return
         */
        public static String getPinYin(String chinese){
            if(TextUtils.isEmpty(chinese))return null;
    
            //输出的格式化对象,用来决定输出字母的大小写,是否带有音标之类
            HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
            format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//设置大写字母
            format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);//设置不带有音汉字进行获取,所以要将字符串转为字符数组,一个一个获取,最后拼接
            StringBuilder builder = new StringBuilder();
            char[] chars = chinese.toCharArray();
    
            for (int i = 0; i < chars.length; i++) {
                char c = chars[i];
                //1.过滤空格
                if(Character.isWhitespace(c)){
                    //如果是空格,则忽略即可
                    continue;
                }
    
                //2.简单判断是否是汉字:一个字节范围是-128~127,所以汉字一定大于127
                if(c > 127){
                    //说明有可能是汉字,那么利用Pinyin4j的api进行获取
                    try {
                        //由于多音字的存在,返回的是数组,比如:单: {dan, chan ,shan}
                        String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(c, format);
                        if(pinyinArr!=null){
                            //问题来了:取哪个拼音?答:暂时只能取第1个
                            //为啥呢?:首先大部分汉字只有一个读音,对于多音字的情况,由于我们实在无能为力去
                            //判断它的真实读音,也只能取第1个罢了。
                            builder.append(pinyinArr[0]);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        //如果异常,说明不是正确的汉字,直接忽略
                    }
                }else {
                    //说明肯定不是汉字,一般是英文字母,我们选择直接拼接
                    builder.append(c);
                }
    
            }
    
            return builder.toString();
        }
    }
    

    3、将数据放到listview上展示

         ①布局如下        

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    
        <ListView
            android:id="@+id/school_friend_member"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:cacheColorHint="@android:color/transparent"
            android:divider="@mipmap/bg_cut_line"
            android:dividerHeight="1px"
            android:fadingEdge="none"
            android:listSelector="@android:color/transparent"
            android:scrollbars="none"></ListView>
    
        <TextView
            android:id="@+id/school_friend_dialog"
            android:layout_width="80.0dip"
            android:layout_height="80.0dip"
            android:layout_gravity="center"
            android:background="@drawable/bg_show_head_toast"
            android:gravity="center"
            android:textColor="#ffffffff"
            android:textSize="30.0dip"
            android:visibility="invisible" />
    
        <com.hiteamtech.ddbes.ui.view.SideBar
            android:id="@+id/school_friend_sidrbar"
            android:layout_width="30dp"
            android:layout_height="match_parent"
            android:layout_gravity="right|center" />
    </FrameLayout>

    ②初始化

    mListView = (ListView) findViewById(R.id.school_friend_member);
    mSideBar = (SideBar) findViewById(R.id.school_friend_sidrbar);
    mDialog = (TextView) findViewById(R.id.school_friend_dialog);
    mSideBar.setOnTouchingLetterChangedListener(this);
    
    mSideBar.setTextView(mDialog);
    

    ③给获取到的集合排序   

    Collections.sort(complete, new Comparator<UserBean>() {
       @Override
       public int compare(UserBean o1, AUserBean o2) {
          String pinying1;
          String pinying2;
          if(o1.getAssetname()!=null){
             pinying1= PinYinUtil.getPinYin(o1.getUserName());
          }else{
             pinying1= PinYinUtil.getPinYin("z");
          }
          if(o2.getAssetname()!=null){
             pinying2= PinYinUtil.getPinYin(o2.getUserName());
          }else{
             pinying2=PinYinUtil.getPinYin("z");
          }
          return pinying1.compareTo(pinying2);
       }
    });

    ④给listview设置adapter

    item布局:

      

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="vertical">
    
        <TextView
            android:id="@+id/catalog"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:background="#F9F9F9"
            android:paddingBottom="5dip"
            android:paddingLeft="5dip"
            android:paddingTop="5dip"
            android:textColor="#454545" />
    
        <TextView
            android:id="@+id/line"
            android:layout_width="fill_parent"
            android:layout_height="1px"
            android:background="@mipmap/bg_cut_line" />
    
        <LinearLayout
            android:id="@+id/content"
            android:layout_width="fill_parent"
            android:layout_height="60dip"
            android:background="@color/white"
            android:orientation="horizontal"
            android:paddingBottom="5dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="5dp">
    
            <com.hiteamtech.ddbes.ui.view.CircleImageView
                android:id="@+id/head"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:layout_marginLeft="10dp"
                android:layout_gravity="center_vertical"
                android:src="@mipmap/headimg_default" />
    
            <TextView
                android:id="@+id/title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dip"
                android:ellipsize="end"
                android:gravity="center_vertical"
                android:singleLine="true"
                android:textColor="#323232"
                android:textSize="16sp"
                tools:text="xxxx" />
        </LinearLayout>
    
    </LinearLayout>

    adapter如下:

    public class InviteFriendListAdapter extends BaseAdapter implements SectionIndexer {
    
        private LayoutInflater inflater;
    
        private Context mContext;
    
        private List<UserBean> list;
    
        public InviteFriendListAdapter(Context context, List<UserBean> list) {
            this.mContext = context;
            this.list = list;
        }
    
        /**
         * 当ListView数据发生变化时,调用此方法来更新ListView
         *
         * @param list
         */
        public void updateListView(List<UserBean> list) {
            this.list = list;
            notifyDataSetChanged();
        }
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null) {
    //            inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                inflater = LayoutInflater.from(mContext);
                convertView = inflater.inflate(R.layout.invitation_friends_item_layout, null);
                holder = new ViewHolder();
                holder.ivHead = (CircleImageView) convertView.findViewById(R.id.head);
                holder.tvTitle = (TextView) convertView.findViewById(R.id.title);
                holder.tvLetter = (TextView) convertView.findViewById(R.id.catalog);
                holder.tvLine = (TextView) convertView.findViewById(R.id.line);
                holder.tvContent = (LinearLayout) convertView.findViewById(R.id.content);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
    
            final UserBean phoneContactBean = list.get(position);
    
            if (phoneContactBean != null) {
                //判断该首字母是否是第一次出现
                if (isfirstshow(position)) {
                    holder.tvLetter.setVisibility(View.VISIBLE);
                    holder.tvLetter.setText(PinYinUtil.getPinYin(mlist.get(position).getUserName()).substring(0,1).toUpperCase());
                    holder.tvLine.setVisibility(View.VISIBLE);
                } else {
                    holder.tvLetter.setVisibility(View.GONE);
                    holder.tvLine.setVisibility(View.GONE);
                }
                holder.tvTitle.setText(phoneContactBean.getUserName());
                
                Glide.with(mContext).load(phoneContactBean.getHeadimg()).asBitmap().error(R.mipmap.headimg_default).into(holder.ivHead);
                holder.tvContent.setOnClickListener(new OnCheckFriendClick(phoneContactBean));
            }
            return convertView;
        }
    
    
        class ViewHolder {
            CircleImageView ivHead;
            TextView tvLetter;
            TextView tvTitle;
            TextView tvLine;
            CheckBox checkFriendCb;
            LinearLayout tvContent;
        }
        
      
        public boolean isfirstshow(int  position) {
            //获取该位置的拼音
            String sectionForPosition = PinYinUtil.getPinYin(mlist.get(position).getUserName());
            //获取首字母
            String firstletter =sectionForPosition.substring(0,1).toUpperCase();
            //判断该位置之前有没有出现过该字母  如果出现过  则不是首次出现,返回false
            for(int i=0;i<position;i++){
                String letter = PinYinUtil.getPinYin(mlist.get(i).getUserName()).substring(0, 1).toUpperCase();
                if(firstletter.equals(letter)){
                    return false;
                }
    
            }
            return true;
        }
       
        public List<UserBean> getList() {
            return list;
        }
    }
    

    4、将sidebar与listview联系起来  当触摸到sidebar的某个字母时  移动到listview首次出现该首字母的位置

    实现SideBar.OnTouchingLetterChangedListener接口

    给sidebar 设置回调 :mSideBar.setOnTouchingLetterChangedListener(this);

    @Override
    public void onTouchingLetterChanged(String s) {
        int position=0;
        for(int i=0;i<mlist.size();i++){
            //获取名字的首字母
            String letter = PinYinUtil.getPinYin(arrayList.get(i).getUserName()).substring(0,1).toUpperCase();
            if(letter.equals(s)){
                //第一次出现的位置
                position=i;
                //将listview滚动到该位置
                mListView.setSelection(position);
                break;
            }
    
        }
    

    小结:文章有点长 ,有问题的地方还希望大家多多指出

    展开全文
  • Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表 代码: 博客:http://blog.csdn.net/zxt0601/article/details/52355199
  • 以前写过一个自定义View,仿微信通讯录列表侧边栏,文章在:Android 仿微信通讯录列表侧边栏 最近又需要使用到它了,就又重新看了一遍代码,修复了几个小bug 而且,既然说的是仿微信,就索性把布局什么的就按照微信...

    以前写过一个自定义View,仿微信通讯录列表侧边栏,文章在:Android 仿微信通讯录列表侧边栏

    最近又需要使用到它了,就又重新看了一遍代码,修复了几个小bug
    而且,既然说的是仿微信,就索性把布局什么的就按照微信的风格来设计
    效果图如下所示


    img_2df47d620e576dd96ee8c186b0b24443.gif
    这里写图片描述

    设计思路可以看我上面给的文章链接,思路挺简单的,大致流程都一样,就修改了一些小地方,这里就不再重复讲了

    这里提供代码下载:Android 仿微信通讯录列表侧边栏

    展开全文
  • Android 仿微信通讯录功能,好友排序 + 字母索引

    万次阅读 多人点赞 2016-05-29 14:58:58
    import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.TextView;...
  • android 仿微信demo————微信启动页实现 android 仿微信demo————注册功能实现(移动端) android 仿微信demo————注册功能实现(服务端) android 仿微信demo————登录功能实现(移动端) android 仿...
  • 第一种就是仿饿了么点餐时,商品列表的悬停头部切换“动画效果”,如下: 第二种是一种头部折叠起来的视效,个人觉得也还不错~如下: 果然比上部残篇里的效果好看多了,那么代码多不多呢,看我的git show 记录: ...
  • * 通讯录字母检索的自定义控件 */ public class AlphaSearchView extends View { private final int ALPHANUM = 27; //字符个数 private final int TEXTSIZE = 30; //字体大小 private int itemHeight; //每...
  • package cn.pocdoc.exam.views; import cn.pocdoc.exam.utils.LogUtil; import cn.pocdoc.exam.R;...import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas;

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,640
精华内容 2,256
关键字:

android仿微信通讯录