精华内容
下载资源
问答
  • 主要为大家详细介绍了Android仿微信通讯录列表侧边栏效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Android微信通讯录效果

    2016-08-07 22:45:57
    android自定义view,实现微信通讯录一模一样的效果
  • 之前的博文《Android 中使用ExpandableListView 实现分组的实例》我简单介绍了使用ExpandableListView实现简单的好友分组功能,今天我们针对之前的所做的仿微信APP来对ExpandableListView做一个扩展介绍,实现效果...

    之前的博文《Android 中使用ExpandableListView 实现分组的实例》我简单介绍了使用ExpandableListView实现简单的好友分组功能,今天我们针对之前的所做的仿微信APP来对ExpandableListView做一个扩展介绍,实现效果如下(通讯里使用ExpandableListView实现):

    相关知识点博文链接:

    b48e354f0101748b31a46f2c9576f2d1.gif

    正常使用ExpandableListView的思路如下:

    (1)要给ExpandableListView 设置适配器,那么必须先设置数据源。

    (2)数据源,就是此处的适配器类ExpandableAdapter,此方法继承了BaseExpandableListAdapter ,它是ExpandableListView的一个子类。需要重写里面的多个方法。方法的意思,代码中都有详细的注释。数据源中,用到了自定义的View布局,此时根据自己的需求,来设置组和子项的布局样式。getChildView()和getGroupView()方法设置自定义布局。

    (3)数据源设置好,直接给 ExpandableListView.setAdapter()即可实现此收缩功能。

    但本次实现除以上实现步骤之外,还需要注意的有以下几点:

    (1)首次加载ExpandableListView需要默认全部展开,使用以下方法:

    在给ExpandableListView 设置适配器后,添加以下代码:

    //Group.size()为组名个数,如果为数组存储则为group、length

    for (int i = 0; i < Group.size(); i++) {

    expandableListView.expandGroup(i);

    }

    提醒:加载前别忘了判断adapter是否为空和有没有Group数据哦

    (2)保持ExpandableListView始终展开无法收缩

    expandableListView.setOnGroupClickListener(new OnGroupClickListener() {

    @Override

    public boolean onGroupClick(ExpandableListView parent, View v,

    int groupPosition, long id) {

    return true;//返回true则表示无法收缩

    }

    });

    (3)取消通讯录上方的groupName空间

    微信通讯录中“新的朋友”,“群聊”,“标签”,“公众号”,作为一个整体自定义布局添加到ExpandableListView中,详情见以下代码实现

    (4)修改ExpandableListView的分割线

    大概思路就是这样,现在开始整体实现代码的演示:

    第一步:layout中通讯录整体布局contactfragment.xml:

    其实就是一个ExpandableListView,添加android:divider ="#FFFFFF"取消自带分割线

    android:orientation="vertical" android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@color/fragmentback">

    android:id="@+id/contact_list"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:layout_alignParentTop="true"

    android:layout_alignParentStart="true"

    android:divider ="#FFFFFF"/>

    第二步:layout中组名(groupName)的布局文件contact_list_group_item.xml:

    注意设置间距,保证美观且尽量与微信一致

    android:orientation="vertical" android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@color/fragmentback">

    android:text="TextView"

    android:textSize="20sp"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:layout_marginLeft="10dp"

    android:gravity="center_vertical"

    android:id="@+id/group_tv" />

    第三步:layout中ExpandableListView中每个item的布局文件contact_list_item.xml:

    这里添加了自定义分割线

    android:orientation="vertical" android:layout_width="match_parent"

    android:layout_height="match_parent">

    android:background="@color/colorwhite"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical">

    android:paddingLeft="10dp"

    android:paddingTop="5dp"

    android:paddingBottom="5dp"

    android:gravity="center_vertical"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">

    android:id="@+id/contact_item_iv"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:src="@mipmap/default_fmessage"

    android:adjustViewBounds="true"

    android:maxWidth="35dp"/>

    android:id="@+id/contact_item_tv"

    android:layout_margin="10dp"

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    android:layout_weight="1"

    android:text="新的朋友"/>

    android:layout_width="match_parent"

    android:layout_height="1dp"

    android:layout_marginLeft="10dp"

    android:layout_marginRight="10dp"

    android:background="@color/fragmentback"/>

    第四步:layout中ExpandableListView中的头布局contact_list_title.xml(不需要groupName)

    我们观察微信通讯录布局中“新的朋友”,“群聊”,“标签”,“公众号”上方直接为微信的顶部导航,不存在ExpandableListView一贯的组名布局,这里我们将“新的朋友”,“群聊”,“标签”的布局单独实现:

    android:orientation="vertical" android:layout_width="match_parent"

    android:layout_height="match_parent">

    android:background="@color/colorwhite"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical">

    android:paddingLeft="10dp"

    android:paddingTop="5dp"

    android:paddingBottom="5dp"

    android:gravity="center_vertical"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:src="@mipmap/default_fmessage"

    android:adjustViewBounds="true"

    android:maxWidth="35dp"/>

    android:layout_margin="10dp"

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    android:layout_weight="1"

    android:text="新的朋友"/>

    android:layout_width="match_parent"

    android:layout_height="1dp"

    android:layout_marginLeft="10dp"

    android:layout_marginRight="10dp"

    android:background="@color/fragmentback"/>

    android:paddingLeft="10dp"

    android:paddingTop="5dp"

    android:paddingBottom="5dp"

    android:gravity="center_vertical"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:src="@mipmap/default_chatroom"

    android:adjustViewBounds="true"

    android:maxWidth="35dp"/>

    android:layout_margin="10dp"

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    android:layout_weight="1"

    android:text="群聊"/>

    android:layout_width="match_parent"

    android:layout_height="1dp"

    android:layout_marginLeft="10dp"

    android:layout_marginRight="10dp"

    android:background="@color/fragmentback"/>

    android:paddingLeft="10dp"

    android:paddingTop="5dp"

    android:paddingBottom="5dp"

    android:gravity="center_vertical"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:src="@mipmap/default_contactlabel"

    android:adjustViewBounds="true"

    android:maxWidth="35dp"/>

    android:layout_margin="10dp"

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    android:layout_weight="1"

    android:text="标签"/>

    android:layout_width="match_parent"

    android:layout_height="1dp"

    android:layout_marginLeft="10dp"

    android:layout_marginRight="10dp"

    android:background="@color/fragmentback"/>

    android:paddingLeft="10dp"

    android:paddingTop="5dp"

    android:paddingBottom="5dp"

    android:gravity="center_vertical"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:orientation="horizontal">

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:src="@mipmap/default_servicebrand_contact"

    android:adjustViewBounds="true"

    android:maxWidth="35dp"/>

    android:layout_margin="10dp"

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    android:layout_weight="1"

    android:text="公众号"/>

    第五步:java中定义继承BaseExpandableListAdapter类(自定义适配器)

    (1)这里模仿实际项目,将自定义适配器定义定义在外部同意管理,所以需要设置相关构造方法供expandableListView调用

    (2)为了实现头文件的布局,需要在getGroupView与getChildView方法中判断头文件的位置,从而调整布局,这里我们将头文件定义在数据首位

    import android.content.Context;

    import android.view.LayoutInflater;

    import android.view.View;

    import android.view.ViewGroup;

    import android.widget.BaseExpandableListAdapter;

    import android.widget.ImageView;

    import android.widget.TextView;

    import com.mly.panhouye.wechat.R;

    /**

    * Created by panchengjia on 2016/12/28 0028.

    */

    public class MyExpandableListAdapter extends BaseExpandableListAdapter {

    Context context;

    String[] group;

    String[][] itemName;

    int[][] itemIcon;

    public MyExpandableListAdapter(Context context, String[] group, String[][] itemName, int[][] itemIcon) {

    this.context = context;

    this.group = group;

    this.itemName = itemName;

    this.itemIcon = itemIcon;

    }

    @Override

    public int getGroupCount() {

    return group.length;

    }

    @Override

    public int getChildrenCount(int groupPosition) {

    return itemName[groupPosition].length;

    }

    @Override

    public Object getGroup(int groupPosition) {

    return group[groupPosition];

    }

    @Override

    public Object getChild(int groupPosition, int childPosition) {

    return itemName[groupPosition][childPosition];

    }

    @Override

    public long getGroupId(int groupPosition) {

    return groupPosition;

    }

    @Override

    public long getChildId(int groupPosition, int childPosition) {

    return childPosition;

    }

    @Override

    public boolean hasStableIds() {

    return false;

    }

    @Override

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {

    ViewHolder vh;

    //ExpandableList的第一个分组没有组名,这里需要自定义布局

    if(groupPosition==0){

    convertView =LayoutInflater.from(context).inflate(R.layout.contact_list_title,null);

    }else{

    if(convertView==null){

    convertView= LayoutInflater.from(context).inflate(R.layout.contact_list_group_item,null);

    vh = new ViewHolder();

    vh.tv = (TextView) convertView.findViewById(R.id.group_tv);

    convertView.setTag(vh);

    }

    vh = (ViewHolder) convertView.getTag();

    vh.tv.setText(group[groupPosition]);

    }

    return convertView;

    }

    @Override

    public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {

    ViewHolder vh;

    //ExpandableList的第一个分组没有组名,这里需要自定义布局

    if (groupPosition==0){

    convertView =LayoutInflater.from(context).inflate(R.layout.contact_list_title,null);

    }else{

    if(convertView==null){

    convertView= LayoutInflater.from(context).inflate(R.layout.contact_list_item,null);

    vh = new ViewHolder();

    vh.tv = (TextView) convertView.findViewById(R.id.contact_item_tv);

    vh.iv= (ImageView) convertView.findViewById(R.id.contact_item_iv);

    convertView.setTag(vh);

    }

    vh = (ViewHolder) convertView.getTag();

    vh.tv.setText(itemName[groupPosition][childPosition]);

    vh.iv.setImageResource(itemIcon[groupPosition][childPosition]);

    }

    return convertView;

    }

    @Override

    public boolean isChildSelectable(int groupPosition, int childPosition) {

    return true;

    }

    class ViewHolder{

    TextView tv;

    ImageView iv;

    }

    }

    第六步:java中重写之前的与contactfragment.xml布局对应的ContactFragment.java类

    import android.os.Bundle;

    import android.support.annotation.Nullable;

    import android.support.v4.app.Fragment;

    import android.view.LayoutInflater;

    import android.view.View;

    import android.view.ViewGroup;

    import android.widget.ExpandableListView;

    import com.mly.panhouye.wechat.R;

    import com.mly.panhouye.wechat.adapter.MyExpandableListAdapter;

    /**

    * Created by panchengjia on 2016/12/28 0028.

    */

    public class ContactFragment extends Fragment {

    private ExpandableListView contact_list;

    //定义分组以及组内成员(设置头文件位置为空)

    String[] group ={"","好友列表"};

    String[][] itemName={{},{"郭嘉", "黄月英", "华佗",

    "刘备", "陆逊", "吕布", "吕蒙", "马超", "司马懿", "孙权", "孙尚香", "夏侯惇",

    "许褚", "杨修", "张飞", "赵云", "甄姬", "周瑜", "诸葛亮"}};

    int[][] itemIcon={{},{R.mipmap.guojia,

    R.mipmap.huangyueying, R.mipmap.huatuo,

    R.mipmap.liubei, R.mipmap.luxun, R.mipmap.lvbu, R.mipmap.lvmeng,

    R.mipmap.machao, R.mipmap.simayi, R.mipmap.sunquan, R.mipmap.sunshangxiang,

    R.mipmap.xiahoudun, R.mipmap.xuchu, R.mipmap.yangxiu, R.mipmap.zhangfei,

    R.mipmap.zhaoyun, R.mipmap.zhenji, R.mipmap.zhouyu, R.mipmap.zhugeliang}};

    @Override

    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.contact_fragment,container,false);

    contact_list = (ExpandableListView) view.findViewById(R.id.contact_list);

    //实例化适配器

    MyExpandableListAdapter myExpandableListAdapter=new MyExpandableListAdapter(getContext(),group,itemName,itemIcon);

    //配置适配器

    contact_list.setAdapter(myExpandableListAdapter);

    //去掉ExpandableListView 默认的箭头

    contact_list.setGroupIndicator(null);

    //设置ExpandableListView默认展开

    for (int i = 0; i

    contact_list.expandGroup(i);

    }

    //设置ExpandableListView不可点击收回

    contact_list.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {

    @Override

    public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {

    return true;

    }

    });

    return view;

    }

    }

    实现方法很多大家开动吧(建议使用recyclerView)。

    以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

    展开全文
  • 以前写过一个自定义View,仿微信通讯录列表侧边栏,文章在:Android 仿微信通讯录列表侧边栏 最近又需要使用到它了,就又重新看了一遍代码,修复了几个小bug 而且,既然说的是仿微信,就索性把布局什么的就按照微信...

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

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


    img_2df47d620e576dd96ee8c186b0b24443.gif
    这里写图片描述

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

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

    展开全文
  • 高仿微信通讯录列表

    千次阅读 2017-11-10 16:32:32
    闲来无事写一个微信通讯录列表demo   思路右侧导航自定义view 中间名字列表list view 直接上代码 右侧导航view /** * Created by wjs on 2017/11/7. * 右侧

    闲来无事写一个微信通讯录列表demo





                                                                    

    思路右侧导航自定义view

    中间名字列表list view

    直接上代码

    右侧导航view

    /**
     * Created by wjs on 2017/11/7.
     * 右侧的导航栏
     */
    public class SideBar extends View {
        private Paint paint = new Paint();
        private int height,width;// 获取对应高度.宽度
        private int singleHeight;// 获取每一个字母的高度
        private int choose = -1;// 选中
        private int oldChoose = choose;
        private String[] index_string ={"↑","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 index_y;
        private float y;
        private TextView mTextDialog;
        // 触摸事件
        private OnTouchChangedListener onTouchChanged;
    
        public void setTextView(TextView mTextDialog) {
            this.mTextDialog = mTextDialog;
        }
        public SideBar(Context context) {
            super(context);
        }
    
        public SideBar(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SideBar(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            height = getHeight();
            width = getWidth();
            singleHeight = height / index_string.length;
            for (int i = 0; i < index_string.length; i++){
                paint.setColor(Color.rgb(33, 65, 98));//给画笔设置颜色值
                paint.setTypeface(Typeface.DEFAULT_BOLD);//
                paint.setAntiAlias(true);//设置画笔是否抗锯齿
                paint.setTextSize(20);
                // 选中的状态
                if (i == choose) {
                    paint.setColor(Color.parseColor("#3399ff"));
                    paint.setFakeBoldText(true);
                }
                // x坐标等于中间-字符串宽度的一半.
                float xPos = width / 2 - paint.measureText(index_string[i]) / 2;
                //y坐标等于n+1个字母的高度
                float yPos = singleHeight * i + singleHeight;
                canvas.drawText(index_string[i], xPos,yPos ,paint);
                paint.reset();// 重置画笔
            }
    
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            OnTouchChangedListener listener = onTouchChanged;
            // 点击y坐标
            y = event.getY();
            // 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
            index_y = (int) (y / getHeight() * index_string.length);
            switch (event.getAction()){
                case MotionEvent.ACTION_UP:
                    setBackgroundDrawable(new ColorDrawable(0x00000000));
                    choose = -1;//
                    invalidate();
                    if (mTextDialog != null) {
                        mTextDialog.setVisibility(View.INVISIBLE);
                    }
                break;
                default:
                    // 设置右侧字母列表[A,B,C,D,E....]的背景颜色
                    setBackgroundResource(R.drawable.sidebar_background);
                    if (oldChoose != index_y) {
                        if (index_y >= 0 && index_y < index_string.length) {
                            if (listener != null) {
                                listener.onTouchChanged(index_string[index_y]);
                            }
                            if (mTextDialog != null) {
                                mTextDialog.setText(index_string[index_y]);
                                mTextDialog.setVisibility(View.VISIBLE);
                            }
    
                            choose = index_y;
                            invalidate();
                        }
                    }
                    break;
            }
    
            return true;
        }
        /**
         * 向外公开的方法
         *
         * @param onTouchChanged
         */
        public void setOnTouchingLetterChangedListener(OnTouchChangedListener onTouchChanged) {
            this.onTouchChanged = onTouchChanged;
        }
        /**
         * 接口
         *
         * @author coder
         *
         */
    
        public interface OnTouchChangedListener {
            public void onTouchChanged(String s);
        }
    }

    mainactivity

    /**
     * 高仿微信列表
     */
    public class MainActivity extends AppCompatActivity {
    
    
        private String ss = "{\"list\":[{\"is_follow\":0,\"nickname\":\"789\",\"user_id\":100,\"avatar\":\"http://image.chaokeli.cn/chocolate/15058077363962.jpg?imageView2/4/w/200\",\"follower_number\":5}],\"total\":3,\"error_code\":0}";
        private SideBar sideBar;
        private TextView dialog;
        private ListView listview;
        private List<nameData.ListEntity> list = new ArrayList<>();//解析出来后的集合
        private List<nameData.ListEntity> nameDatasList;//排序好的集合
        private SearchAdapter adapter;
        /**
         * 汉字转换成拼音的类
         */
        private CharacterParser characterParser;
        /**
         * 根据拼音来排列ListView里面的数据类
         * 拼音比较器
         */
        private PinyinComparator pinyinComparator = new PinyinComparator();
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
            initData();
        }
    
        private void initView() {
            sideBar = (SideBar) findViewById(R.id.sideBar);
            dialog = (TextView) findViewById(R.id.dialog);
            listview = (ListView) findViewById(R.id.listview);
            sideBar.setTextView(dialog);
        }
    
        private void initData() {
            // 实例化汉字转拼音类
            characterParser = CharacterParser.getInstance();
            Gson gson = new Gson();
            nameData namedata = gson.fromJson(ss, nameData.class);
            list.addAll(namedata.getList());
            //汉子转换成拼音
            nameDatasList = zi2pinyi(list);
    
            // 根据a-z进行排序源数据
            Collections.sort(nameDatasList, pinyinComparator);
            for (int i = 0; i < 4; i++) {
                nameData.ListEntity listEntity = new nameData.ListEntity();
                if (i == 3) {
                    listEntity.setNickname("新朋友");
                    listEntity.setSortLetters("↑");
                    nameDatasList.add(0, listEntity);
                } else if (i == 2) {
                    listEntity.setNickname("群聊");
                    listEntity.setSortLetters("↑");
                    nameDatasList.add(0, listEntity);
                } else if (i == 1) {
                    listEntity.setNickname("标签");
                    listEntity.setSortLetters("↑");
                    nameDatasList.add(0, listEntity);
                } else if (i == 0) {
                    listEntity.setNickname("公众号");
                    listEntity.setSortLetters("↑");
                    nameDatasList.add(0, listEntity);
                }
    
            }
    
            adapter = new SearchAdapter(MainActivity.this, nameDatasList);
            listview.setAdapter(adapter);
            //右侧导航条目的触摸监听
            onSideBarListener();
            //listview点击事件
            onListviewListener();
        }
    
        /**
         * listview点击事件
         */
        private void onListviewListener() {
            listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    Toast.makeText(MainActivity.this, nameDatasList.get(i).getNickname() + "   item:" + i,
                            Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        private List<nameData.ListEntity> zi2pinyi(List<nameData.ListEntity> list) {
    
            for (int i = 0; i < list.size(); i++) {
                // 汉字转换成拼音
                String pinyin = characterParser.getSelling(list.get(i).getNickname());
                String sortString = pinyin.substring(0, 1).toUpperCase();
                // 正则表达式,判断首字母是否是英文字母
                if (sortString.matches("[A-Z]")) {
                    list.get(i).setSortLetters(sortString.toUpperCase());
                } else {
                    list.get(i).setSortLetters("#");
                }
            }
            return list;
        }
    
        /**
         * 右侧导航条目的触摸监听
         */
        private void onSideBarListener() {
            sideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchChangedListener() {
                @Override
                public void onTouchChanged(String s) {
                    //点击字母出现在当前页面
                    int position = adapter.getPositionForSection(s.charAt(0));
                    if (position != -1) {
                        listview.setSelection(position);
                    }
                }
            });
        }
    }
     adapter

    /**
     * Created by wjs on 2017/11/7.
     * 人名
     */
    public class SearchAdapter extends BaseAdapter {
        private List<nameData.ListEntity> list = null;
        private Context context;
    
        public SearchAdapter(Context context, List<nameData.ListEntity> list) {
            this.context = context;
            this.list = list;
        }
    
        @Override
        public int getCount() {
            if (list.size() > 0) {
                return list.size();
            } else {
                return 0;
            }
    
        }
    
        @Override
        public Object getItem(int i) {
            return list.get(i);
        }
    
        @Override
        public long getItemId(int i) {
            return i;
        }
    
        @Override
        public View getView(int position, View view, ViewGroup viewGroup) {
            ViewHolder viewHolder = null;
    
            if (view == null) {
                viewHolder = new ViewHolder();
                view = LayoutInflater.from(context).inflate(R.layout.item_listview, viewGroup, false);
                viewHolder.name = (TextView) view.findViewById(R.id.name);
                viewHolder.iv = (ImageView) view.findViewById(R.id.iv);
                viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);
                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }
    
            // 根据position获取分类的首字母的Char ascii值
            int section = getSectionForPosition(position);
            // 如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
            if (position == getPositionForSection(section)) {
                if (list.get(position).getSortLetters().equals("↑")){
                    viewHolder.tvLetter.setVisibility(View.GONE);
                }else {
                    viewHolder.tvLetter.setVisibility(View.VISIBLE);
                    viewHolder.tvLetter.setText(list.get(position).getSortLetters());
                }
    
            } else {
                viewHolder.tvLetter.setVisibility(View.GONE);
            }
    
            viewHolder.name.setText(list.get(position).getNickname());
            Glide.with(context)
                    .load(R.mipmap.ic_launcher)
                    .into(viewHolder.iv);
    
            return view;
        }
    
        final static class ViewHolder {
            TextView name;
            ImageView iv;
            TextView tvLetter;
    
        }
    
        /**
         * 根据ListView的当前位置获取分类的首字母的Char ascii值
         */
        public int getSectionForPosition(int position) {
            return list.get(position).getSortLetters().charAt(0);
        }
    
        /**
         * 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
         */
        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;
        }
    


    首个字转拼音

    /**
     * Created by wjs on 2017/11/7.
     */
    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());
       }
    
    }


    点击查看完整代码

    转载声明出处:http://blog.csdn.net/qq_35698774/article/details/78501061

    学习互助群:471761982



    展开全文
  • 列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位 实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包——pinyin4j-2.5.0即可 首先,先来定义侧...

    先看效果图

    img_ac41a9fb2b8b59f2240f86b7d9b7f422.gif
    这里写图片描述

    这是比较常见的效果了吧
    列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位

    实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包——pinyin4j-2.5.0即可

    首先,先来定义侧边栏控件View,只要直接画出来即可
    字母选中项会变为红色,且滑动时背景会变色,此时SideBar并不包含居中的提示文本

    public class SideBar extends View {
    
        private Paint paint = new Paint();
    
        private int choose = -1;
    
        private boolean showBackground;
    
        public static 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 OnChooseLetterChangedListener onChooseLetterChangedListener;
    
        public SideBar(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public SideBar(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SideBar(Context context) {
            super(context);
        }
    
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            if (showBackground) {
                canvas.drawColor(Color.parseColor("#D9D9D9"));
            }
            int height = getHeight();
            int width = getWidth();
            //平均每个字母占的高度
            int singleHeight = height / letters.length;
            for (int i = 0; i < letters.length; i++) {
                paint.setColor(Color.BLACK);
                paint.setAntiAlias(true);
                paint.setTextSize(25);
                if (i == choose) {
                    paint.setColor(Color.parseColor("#FF2828"));
                    paint.setFakeBoldText(true);
                }
                float x = width / 2 - paint.measureText(letters[i]) / 2;
                float y = singleHeight * i + singleHeight;
                canvas.drawText(letters[i], x, y, paint);
                paint.reset();
            }
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            int action = event.getAction();
            float y = event.getY();
            int oldChoose = choose;
            int c = (int) (y / getHeight() * letters.length);
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    showBackground = true;
                    if (oldChoose != c && onChooseLetterChangedListener != null) {
                        if (c > -1 && c < letters.length) {
                            onChooseLetterChangedListener.onChooseLetter(letters[c]);
                            choose = c;
                            invalidate();
                        }
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (oldChoose != c && onChooseLetterChangedListener != null) {
                        if (c > -1 && c < letters.length) {
                            onChooseLetterChangedListener.onChooseLetter(letters[c]);
                            choose = c;
                            invalidate();
                        }
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    showBackground = false;
                    choose = -1;
                    if (onChooseLetterChangedListener != null) {
                        onChooseLetterChangedListener.onNoChooseLetter();
                    }
                    invalidate();
                    break;
            }
            return true;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            return super.onTouchEvent(event);
        }
    
        public void setOnTouchingLetterChangedListener(OnChooseLetterChangedListener onChooseLetterChangedListener) {
            this.onChooseLetterChangedListener = onChooseLetterChangedListener;
        }
    
        public interface OnChooseLetterChangedListener {
    
            void onChooseLetter(String s);
    
            void onNoChooseLetter();
    
        }
    
    }
    

    SideBar只是画出了侧边栏索引条而已,不包含居中的提示文本,这个在另一个布局添加即可

    public class HintSideBar extends RelativeLayout implements SideBar.OnChooseLetterChangedListener {
    
        private TextView tv_hint;
    
        private SideBar.OnChooseLetterChangedListener onChooseLetterChangedListener;
    
        public HintSideBar(Context context, AttributeSet attrs) {
            super(context, attrs);
            LayoutInflater.from(context).inflate(R.layout.view_hint_side_bar, this);
            initView();
        }
    
        private void initView() {
            SideBar sideBar = (SideBar) findViewById(R.id.sideBar);
            tv_hint = (TextView) findViewById(R.id.tv_hint);
            sideBar.setOnTouchingLetterChangedListener(this);
        }
    
        @Override
        public void onChooseLetter(String s) {
            tv_hint.setText(s);
            tv_hint.setVisibility(VISIBLE);
            if (onChooseLetterChangedListener != null) {
                onChooseLetterChangedListener.onChooseLetter(s);
            }
        }
    
        @Override
        public void onNoChooseLetter() {
            tv_hint.setVisibility(INVISIBLE);
            if (onChooseLetterChangedListener != null) {
                onChooseLetterChangedListener.onNoChooseLetter();
            }
        }
    
        public void setOnChooseLetterChangedListener(SideBar.OnChooseLetterChangedListener onChooseLetterChangedListener) {
            this.onChooseLetterChangedListener = onChooseLetterChangedListener;
        }
    }
    

    HintSideBar通过回调接口来更新居中TextView的文本内容和可见性

    使用到的布局

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.czy.demo.SideBar
            android:id="@+id/sideBar"
            android:layout_width="30dp"
            android:layout_height="match_parent"
            android:layout_alignParentRight="true" />
    
        <TextView
            android:id="@+id/tv_hint"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:layout_centerInParent="true"
            android:background="#4b0e0e0e"
            android:gravity="center"
            android:textColor="#ffffff"
            android:textSize="30sp"
            android:visibility="invisible" />
    
    </RelativeLayout>
    

    此时就完成了索引View的绘制,不过定位功能还需要再通过回调接口来完成

    引入jar包后,先来设定一个工具类,包含一个可以解析字符串的方法,返回值为首字符对应的拼音首字母或者为包含一个空格的char类型数据

    public class Utils {
    
        /**
         * 如果字符串的首字符为汉字,则返回该汉字的拼音大写首字母
         * 如果字符串的首字符为字母,也转化为大写字母返回
         * 其他情况均返回' '
         *
         * @param str 字符串
         * @return 首字母
         */
        public static char getHeadChar(String str) {
            if (str != null && str.trim().length() != 0) {
                char[] strChar = str.toCharArray();
                char headChar = strChar[0];
                //如果是大写字母则直接返回
                if (Character.isUpperCase(headChar)) {
                    return headChar;
                } else if (Character.isLowerCase(headChar)) {
                    return Character.toUpperCase(headChar);
                }
                // 汉语拼音格式输出类
                HanyuPinyinOutputFormat hanYuPinOutputFormat = new HanyuPinyinOutputFormat();
                hanYuPinOutputFormat.setCaseType(UPPERCASE);
                hanYuPinOutputFormat.setToneType(WITHOUT_TONE);
                if (String.valueOf(headChar).matches("[\\u4E00-\\u9FA5]+")) {
                    try {
                        String[] stringArray = PinyinHelper.toHanyuPinyinStringArray(headChar, hanYuPinOutputFormat);
                        if (stringArray != null && stringArray[0] != null) {
                            return stringArray[0].charAt(0);
                        }
                    } catch (BadHanyuPinyinOutputFormatCombination e) {
                        return ' ';
                    }
                }
            }
            return ' ';
        }
    
    }
    

    然后再定义一个实体类,包含用户名,电话,用户名首字符的拼音首字母等三个属性
    需要实现Comparable 接口,用于排序

    public class User implements Comparable {
    
        private String userName;
    
        private String phone;
    
        private char headLetter;
    
        public User(String userName, String phone) {
            this.userName = userName;
            this.phone = phone;
            headLetter = Utils.getHeadChar(userName);
        }
    
        public String getUserName() {
            return userName;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public char getHeadLetter() {
            return headLetter;
        }
    
        @Override
        public boolean equals(Object object) {
            if (this == object) {
                return true;
            }
            if (object == null || getClass() != object.getClass()) {
                return false;
            }
            User that = (User) object;
            return getUserName().equals(that.getUserName()) && getPhone().equals(that.getPhone());
        }
    
        @Override
        public int compareTo(Object object) {
            if (object instanceof User) {
                User that = (User) object;
                if (getHeadLetter() == ' ') {
                    if (that.getHeadLetter() == ' ') {
                        return 0;
                    }
                    return -1;
                }
                if (that.getHeadLetter() == ' ') {
                    return 1;
                } else if (that.getHeadLetter() > getHeadLetter()) {
                    return -1;
                } else if (that.getHeadLetter() == getHeadLetter()) {
                    return 0;
                }
                return 1;
            } else {
                throw new ClassCastException();
            }
        }
    
    }
    

    主布局文件如下

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_userList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <com.czy.demo.HintSideBar
            android:id="@+id/hintSideBar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="right" />
    
    </FrameLayout>
    
    
    

    联系人列表使用的是RecyclerView,还需要定义一个Adapter

    public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserHolder> {
    
        private List<User> userList;
    
        private LayoutInflater inflater;
    
        public UserAdapter(Context context) {
            inflater = LayoutInflater.from(context);
            userList = new ArrayList<>();
        }
    
        @Override
        public UserHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = inflater.inflate(R.layout.item_user, parent, false);
            return new UserHolder(view);
        }
    
        @Override
        public void onBindViewHolder(UserHolder holder, int position) {
            holder.tv_userName.setText(userList.get(position).getUserName());
            holder.tv_phone.setText(userList.get(position).getPhone());
        }
    
        public void setData(List<User> userList) {
            this.userList.clear();
            this.userList = userList;
        }
    
        public int getFirstPositionByChar(char sign) {
            if (sign == '#') {
                return 0;
            }
            for (int i = 0; i < userList.size(); i++) {
                if (userList.get(i).getHeadLetter() == sign) {
                    return i;
                }
            }
            return -1;
        }
    
        @Override
        public int getItemCount() {
            return userList.size();
        }
    
        class UserHolder extends RecyclerView.ViewHolder {
    
            public TextView tv_userName;
    
            public TextView tv_phone;
    
            public UserHolder(View itemView) {
                super(itemView);
                tv_userName = (TextView) itemView.findViewById(R.id.tv_userName);
                tv_phone = (TextView) itemView.findViewById(R.id.tv_phone);
            }
        }
    
    }
    

    以下方法用于获取联系人列表中第一个首字符为sign的item的位置

    public int getFirstPositionByChar(char sign)
    

    主Activity代码如下

    public class MainActivity extends AppCompatActivity implements SideBar.OnChooseLetterChangedListener {
    
        private List<User> userList;
    
        private UserAdapter adapter;
    
        private RecyclerView rv_userList;
    
        private LinearLayoutManager manager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
            setContentView(R.layout.activity_main);
            HintSideBar hintSideBar = (HintSideBar) findViewById(R.id.hintSideBar);
            rv_userList = (RecyclerView) findViewById(R.id.rv_userList);
            hintSideBar.setOnChooseLetterChangedListener(this);
            manager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
            rv_userList.setLayoutManager(manager);
            userList = new ArrayList<>();
            adapter = new UserAdapter(this);
            initData();
            adapter.setData(userList);
            rv_userList.setAdapter(adapter);
        }
    
        @Override
        public void onChooseLetter(String s) {
            int i = adapter.getFirstPositionByChar(s.charAt(0));
            if (i == -1) {
                return;
            }
            manager.scrollToPositionWithOffset(i, 0);
        }
    
        @Override
        public void onNoChooseLetter() {
    
        }
    }
    

    initData()用于向Adapter填充数据

    public void initData() {
            User user1 = new User("陈", "12345678");
            User user2 = new User("赵", "12345678");
            ...
            userList.add(user1);
            userList.add(user2);
            ...
            Collections.sort(userList);
            adapter.notifyDataSetChanged();
        }
    

    这样,整个效果就都完成了

    代码我已上传到GitHub——HintSideBar

    展开全文
  • Android仿微信通讯录侧边栏
  • 主要介绍了Android 仿微信通讯录导航分组列表,使用ItemDecoration为RecyclerView打造带悬停头部的分组列表,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 前言 提前祝大家元旦快乐,恭喜发财! 深夜来一发,2015年最后一篇博客。 差不多一个月没写博客了,最近开始实习了,空闲时间少了,人也变懒了^_^ 今天来个比较简单的,先看效果图。 ...public class IndexBar ...
  • 主要介绍了Android仿微信通讯录滑动快速定位功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表,修改bug版本.zip 【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部...
  • 仿微信通讯录列表

    2014-08-19 15:44:16
    这是一个简单的Demo,因为字母排序的缘故,想让listview随字母侧边栏拖动,所有只能有一个listview,这里提供实现将两个listview组合起来,上面是群组管理,下面是通讯录联系人排序
  • Android仿微信通讯录

    千次阅读 2019-09-24 10:06:08
    Android仿微信通讯录 分3部: 1、listview实现显示头像、名字(太简单,这里就不写了) 通讯录页面xml布局代码: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:...
  • *本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 【Android 仿微信通讯录 导航分组列表-上】使用ItemDecoration为RecyclerView打造带悬停头部的分组列表一 概述本文是Android导航分组列表系列上,因时间和...
  • android 仿微信demo————微信启动页实现 android 仿微信demo————注册功能实现(移动端) android 仿微信demo————注册功能实现(服务端) android 仿微信demo————登录功能实现(移动端) android 仿...
  • 上次的博客中实现了微信通讯录的效果后 微信通讯录效果,现在给通讯录联系人增加长按弹出上下文菜单功能,效果如下:功能和实现也比较简单,步骤如下: 第一步:调用方法registerForContextMenu() 注册你要弹出浮动...
  • 今天的智能手机对一切都有好处,但它们很...事实上,我们现在在微信上找不到通讯录备份功能是很正常的,因为通讯录备份是以前老版本微信的一个辅助功能。像微信运动一样,新版本现在已经消失了。这样,新版微信如何...
  • 模仿了一下微信的联系人界面UI,由于是新手,所以看起来很简单的界面,结果被搞得半死,弄到凌晨5点,实在吃不消了,就睡了,早上9点又有...先来一张原版的微信通讯录截图 对,界面就是这样的,很熟悉的界面吧,下面就
  • 在如今的智能手机时代,备份通讯录变得相当方便,我们如果是手机丢了...微信通讯录备份在哪里微信有一项特别好用的功能,那就是“通讯录安全助手",只是它潜伏在软件中一个很神秘的地方,很多人都不知道在哪里。微信...
  • 本篇文章主要介绍了android仿微信通讯录搜索示例(匹配拼音,字母,索引位置),具有一定的参考价值,有兴趣的可以了解一下
  • Android 仿微信通讯录 导航分组列表-下】自定义View为RecyclerView打造右侧索引导航栏IndexBar
  • 本文主要介绍了Android自定义View实现通讯录字母索引(仿微信通讯录)的实现步骤与方法,具有很好的参考价值,下面跟着小编一起来看下吧
  • 本文主要介绍了Android中使用Expandablelistview实现微信通讯录界面(完善防微信APP)的方法,具有一定的参考价值,下面跟着小编一起来看下吧

空空如也

空空如也

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

android微信通讯录列表