联系人快速索引

2018-10-02  本文已影响23人  GeekGray

阅读原文

联系人快速索引

1.界面布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.contactquickindex.MainActivity">

    <ListView
        android:id="@+id/lv_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@+id/tv_word"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_centerInParent="true"
        android:background="#44000000"
        android:gravity="center"
        android:text="A"
        android:textColor="#000000"
        android:textSize="30sp"
        android:visibility="gone" />

    <com.contactquickindex.IndexView
        android:id="@+id/iv_words"
        android:layout_width="30dp"
        android:layout_height="match_parent"
        android:layout_alignParentRight="true"
        android:background="#ff0000" />
</RelativeLayout>

2.初始化显示字母列表

1.自定义IndexView继承于View

/**
 * 
 * @author: Hashub.NG
 * @description: 绘制快速索引的字母 1.把26个字母放入数组 2.在onMeasure计算每条的高itemHeight和宽itemWidth,
 *               3.在onDraw和wordWidth,wordHeight,wordX,wordY
 *               <p/>
 *               手指按下文字变色 1.重写onTouchEvent(),返回true,在down/move的过程中计算 int
 *               touchIndex = Y / itemHeight; 强制绘制
 *               <p/>
 *               2.在onDraw()方法对于的下标设置画笔变色
 *               <p/>
 *               3.在up的时候 touchIndex = -1; 强制绘制
 * @update: 2018年8月1日 下午7:43:44
 */
public class IndexView extends View{}

2.定义变量

    /**
     * 每条的宽和高
     */
    private int itemWidth;
    private int itemHeight;

    private Paint paint;

    private String[] words = { "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" };

3.初始化字母位置

    public IndexView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.WHITE);// 设置颜色
        paint.setAntiAlias(true);// 设置抗锯齿
        paint.setTypeface(Typeface.DEFAULT_BOLD);// 设置粗体字
    }

    /**
     * 测量方法
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        itemWidth = getMeasuredWidth();
        itemHeight = getMeasuredHeight() / words.length;
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        for (int i = 0; i < words.length; i++)
        {
            if (touchIndex == i)
            {
                // 设置灰色
                paint.setColor(Color.GRAY);
            }
            else
            {
                // 设置白色
                paint.setColor(Color.WHITE);
            }
            String word = words[i];// A
            Rect rect = new Rect();
            // 画笔
            // 0,1的取一个字母
            paint.getTextBounds(word, 0, 1, rect);

            // 字母的高和宽
            int wordWidth = rect.width();
            int wordHeight = rect.height();

            // 计算每个字母在视图上的坐标位置
            float wordX = itemWidth / 2 - wordWidth / 2;
            float wordY = itemHeight / 2 - wordHeight / 2 + i * itemHeight;

            canvas.drawText(word, wordX, wordY, paint);

        }
    }

3.在按下和移动的时候使操作字母变色

实现步骤分析

.在按下和移动时候,使操作的字母变色

a.重写onTouchEvent(),返回true

b.在down/move时,计算出操作的下标,并且在onDraw(),设置不同颜色画笔,强制绘制

c.在up时,重置操作下标,强制重绘制

        /**
         * 字母的下标位置
         */
        private int touchIndex = -1;

    /**
     * 手指按下文字变色
     * 1.重写onTouchEvent(),返回true,在down/move的过程中计算
     * int touchIndex = Y / itemHeight; 强制绘制
     * <p/>
     * 2.在onDraw()方法对于的下标设置画笔变色
     * <p/>
     * 3.在up的时候
     * touchIndex  = -1;
     * 强制绘制
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
         super.onTouchEvent(event);
         switch (event.getAction())
        {
        case MotionEvent.ACTION_DOWN://Down和Move都需要处理,不需要break

        case MotionEvent.ACTION_MOVE:
            float Y=event.getY();
            int index=(int) (Y/itemHeight);//字母索引
            if(index!=touchIndex)
            {
                touchIndex=index;
                invalidate();//强制绘制onDraw();
                if(onIndexChangeListener!=null && touchIndex<words.length)//判空及防止数组越界
                {
                    onIndexChangeListener.onIndexChange(words[touchIndex]);
                }
            }
            break;

        case MotionEvent.ACTION_UP:
            touchIndex=-1;
            invalidate();
            break;
        }
         return true;
    }

4.在按下和移动时显示更新提示字母

使用接口,封装变化,供外界调用

    /**
     * 字母下标索引变化的监听器
     */
    public interface OnIndexChangeListener
    {
        /**
         * 当字母下标位置发生变化的时候回调
         * 
         * @param word
         *            字母(A~Z)
         */
        void onIndexChange(String word);
    }

    /**
     * 设置字母下标索引变化的监听
     * 把接口写成类的成员变量,提供set方法
     * @param onIndexChangeListener
     */
    public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener)
    {
        this.onIndexChangeListener = onIndexChangeListener;
    }

在MainActivity中使用接口

    private ListView lv_main;
    private TextView tv_word;
    private IndexView iv_words;

    private Handler handler = new Handler();
    /**
     * 联系人的集合
     */
    private ArrayList<Person> persons;
    private  IndexAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv_main = (ListView) findViewById(R.id.lv_main);
        tv_word = (TextView) findViewById(R.id.tv_word);
        iv_words = (IndexView) findViewById(R.id.iv_words);
        //设置监听字母下标索引的变化
        iv_words.setOnIndexChangeListener(new MyOnIndexChangeListener());
        //准备数据
        initData();
        //设置适配器
        adapter = new IndexAdapter();
        lv_main.setAdapter(adapter);
    }

使用handler延迟隐藏

        //显示
        tv_word.setVisibility(View.VISIBLE);
        tv_word.setText(word);
        handler.removeCallbacksAndMessages(null);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //也是运行在主线程
                System.out.println(Thread.currentThread().getName()+"------------");

                tv_word.setVisibility(View.GONE);
            }
        }, 3000);

5.列表显示联系人

导入汉字转拼音jar包和工具类

public class PinYinUtils
{
    /**
     * 得到指定汉字的拼音 注意:不应该被频繁调用,它消耗一定内存
     * 
     * @param hanzi
     * @return
     */
    public static String getPinYin(String hanzi)
    {
        String pinyin = "";

        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();// 控制转换是否大小写,是否带音标
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);// 大写
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

        // 由于不能直接对多个汉字转换,只能对单个汉字转换
        char[] arr = hanzi.toCharArray();
        for (int i = 0; i < arr.length; i++)
        {
            if (Character.isWhitespace(arr[i]))
                continue;// 如果是空格,则不处理,进行下次遍历

            // 汉字是2个字节存储,肯定大于127,所以大于127就可以当为汉字转换
            if (arr[i] > 127)
            {
                try
                {
                    // 由于多音字的存在,单 dan shan
                    String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(arr[i], format);

                    if (pinyinArr != null)
                    {
                        pinyin += pinyinArr[0];
                    }
                    else
                    {
                        pinyin += arr[i];
                    }
                }
                catch (BadHanyuPinyinOutputFormatCombination e)
                {
                    e.printStackTrace();
                    // 不是正确的汉字
                    pinyin += arr[i];
                }
            }
            else
            {
                // 不是汉字,
                pinyin += arr[i];
            }
        }
        return pinyin;
    }
}

Person bean类

public class Person
{

    private String name;

    private String pinyin;

    public Person(String name)
    {
        this.name = name;
        this.pinyin = PinYinUtils.getPinYin(name);
    }

    public String getPinyin()
    {
        return pinyin;
    }

    public void setPinyin(String pinyin)
    {
        this.pinyin = pinyin;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return "Person{" + "name='" + name + '\'' + ", pinyin='" + pinyin + '\'' + '}';
    }
}

初始化联系人列表数据

    /**
     * 初始化数据
     */
    private void initData() {

        persons = new ArrayList<Person>();
        persons.add(new Person("张晓飞"));
        persons.add(new Person("杨光福"));
        persons.add(new Person("胡继群"));
        persons.add(new Person("刘畅"));

        persons.add(new Person("钟泽兴"));
        persons.add(new Person("尹革新"));
        persons.add(new Person("安传鑫"));
        persons.add(new Person("张骞壬"));

        persons.add(new Person("温松"));
        persons.add(new Person("李凤秋"));
        persons.add(new Person("刘甫"));
        persons.add(new Person("娄全超"));
        persons.add(new Person("张猛"));

        persons.add(new Person("王英杰"));
        persons.add(new Person("李振南"));
        persons.add(new Person("孙仁政"));
        persons.add(new Person("唐春雷"));
        persons.add(new Person("牛鹏伟"));
        persons.add(new Person("姜宇航"));

        persons.add(new Person("刘挺"));
        persons.add(new Person("张洪瑞"));
        persons.add(new Person("张建忠"));
        persons.add(new Person("侯亚帅"));
        persons.add(new Person("刘帅"));

        persons.add(new Person("乔竞飞"));
        persons.add(new Person("徐雨健"));
        persons.add(new Person("吴亮"));
        persons.add(new Person("王兆霖"));

        persons.add(new Person("阿三"));
        persons.add(new Person("李博俊"));

联系人列表排序

        //排序
        Collections.sort(persons, new Comparator<Person>() {
            @Override
            public int compare(Person lhs, Person rhs) {
                return lhs.getPinyin().compareTo(rhs.getPinyin());
            }
        });

item_main.xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_word"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#44000000"
        android:text="A"
        android:textColor="#000000"
        android:textSize="25sp" />

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="阿福"
        android:textColor="#000000"
        android:textSize="25sp" />


</LinearLayout>

listview填充数据显示

 class IndexAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return persons.size();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder viewHolder;
            if(convertView ==null){
                convertView = View.inflate(MainActivity.this,R.layout.item_main,null);
                viewHolder = new ViewHolder();
                viewHolder.tv_word = (TextView) convertView.findViewById(R.id.tv_word);
                viewHolder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);
                convertView.setTag(viewHolder);
            }else{
                viewHolder = (ViewHolder) convertView.getTag();
            }

            String name = persons.get(position).getName();//阿福
            String word = persons.get(position).getPinyin().substring(0,1);//AFU->A
            viewHolder.tv_word.setText(word);
            viewHolder.tv_name.setText(name);
            if(position ==0){
                viewHolder.tv_word.setVisibility(View.VISIBLE);
            }else{
                //得到前一个位置对应的字母,如果当前的字母和上一个相同,隐藏;否则就显示
                String preWord = persons.get(position-1).getPinyin().substring(0,1);//A~Z
                if(word.equals(preWord)){
                    viewHolder.tv_word.setVisibility(View.GONE);
                }else{
                    viewHolder.tv_word.setVisibility(View.VISIBLE);
                }


            }


            return convertView;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }


    }

    static class ViewHolder{
        TextView tv_word;
        TextView tv_name;
    }

6.在按下和移动是列表更新

更新列表

 private void updateListView(String word) {
        for(int i=0;i<persons.size();i++){
            String listWord = persons.get(i).getPinyin().substring(0,1);//YANGGUANGFU-->Y
            if (word.equals(listWord)) {
                //i是listView中的位置
                lv_main.setSelection(i);//定位到ListVeiw中的某个位置
                return;
            }
        }
    }
上一篇下一篇

猜你喜欢

热点阅读