安卓仿手机联系人右侧快速搜索菜单自定义View

今天练习了一下手机联系人快速索引的自定义View,依例看下效果图:

先来张极具爆发力的大月亮珠联璧合组合:
这里写图片描述

效果图:

这里写图片描述

观今夜星,额不,观效果很多同学一下子可能感觉很复杂,没错,确实蛮复杂的。不过分析一下就很简单了,整个布局分为三块:

  1. 铺满屏幕的列表控件(这里用的是Recycleview)
  2. 中间显示字幕的正方形
  3. 右侧可滑动、点击的不知啥玩意

完成布局除了右侧的东西其他都很简单,那么重点就是在右侧的滑动控件了,没错,这玩意就是这个效果的最主要成员,暂且命名其为IndexWord(字幕索引),下面我们一步步来实现效果:

1.IndexWord自定义的初始化以及字幕的呈现

public class IndexWord extends View {

    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"};
    private TextPaint textPaint;//文本画笔
    private int everywidth;//每一个字母单元格的宽度
    private int length;//words长度,
    private int everyheght;//每一个字母单元格的高度
    private Rect rect;//矩形
    private int index = -1;//用于touchevent中记录点击的是哪个字幕

    public IndexWord(Context context) {
        this(context, null);
    }

    public IndexWord(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public IndexWord(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initpaint();


    }

当然这里的words可以通过各种途径获得到,看属性就知道不怎么复杂,主要是怎么把字幕(汉子也可以)平均的画出来,那么问题转化为如何获得每个字母的坐标x,y了。自古文字留不住,唯有图片得人心,看一下下图应该就理解了:
这里写图片描述

drawtext中 x,y的坐标是可以更改的,需要注意的是默认情况下y的坐标是底线上的坐标值,

下面是onDraw中的代码:

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        initheight();
        for (int i = 0; i < length; i++) {
            String word = words[i];
            textPaint.getTextBounds(word, 0, 1, rect);
            int width = rect.width();
            int height = rect.height();
            if (index == i) {
                textPaint.setColor(Color.RED);
            } else {
                textPaint.setColor(Color.BLACK);
            }
            canvas.drawText(word, everywidth / 2 - width / 2, everyheght * i+(everyheght/2+        height/2), textPaint);
        }

    }

这样就把各个字幕画在 了控件上,里面的之所以有if判断,待会会讲到。

2.点击滑动事件的添加

仔细看的同学应该注意到了,当点击或者滑动到某个字母的时候,改字幕是要变色的,自然而然的就要处理触屏事件了,重写onTouchEvent方法如下:

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN|MotionEvent.ACTION_MOVE:
                index = (int) (event.getY() / everyheght);
                if (indexPressWord != null && index >= 0) {
                    indexPressWord.setIndexPressWord(words[index]);
                }
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                index = -1;
                invalidate();
                break;
            default:
        }
        return true;
    }

当某个子母被点击或者滑到的时候,通过index = (int) (event.getY() / everyheght)得到他是哪个字幕,也就是下标,然后调用invalidate()方法重走onDraw方法,在通过if判断,如果点击的是这个字幕 改变 画笔的颜色,这样就实现了效果。

3.中间正方形字幕的实现

其实,上一步重写onTouchEvent的时候我们已经得到了点击的字幕,这个时候我们只是要把他在正方形中呈现出来而已,那么就很容易实现了,直接通过接口会调就实现了,上一步骤中已经给出了回调:indexPressWord.setIndexPressWord(words[index]),直接在主线程中就可以set出来,让正方形出现三秒再消失,这里的方法有很多很多,我用的是handler,下面是主要代码:

    private void setTvWord() {
        iwMain.setIndexPressWord(new IndexWord.IndexPressWord() {
            @Override
            public void setIndexPressWord(String word) {
                tvMain.setVisibility(View.VISIBLE);
                tvMain.setText(word);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        tvMain.setVisibility(View.GONE);
                    }
                }, 2000);
            }
        });
    }

一看应该就会很明白了

4.Recycleview呈现数据源,以及跳到制定字幕的实现

这里就不贴代码了,说一下实现思路,还是看张图片:

这里写图片描述

全是套路,哈哈,只是把那些不该看到的东西隐藏掉了而已,当然如果觉得自己很牛叉,可以试试recycleview的多布局,保证会写吐。
这里的阿虎阿猫以及A、B是Perdon类的属性;Person类如下:

public class Person {

    private String name;

    private String pinyin;

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

代码中的PersonUtils是专门把汉子转换为拼音的工具类,我们截取拼音的第一位就得到了A、B,很容易。

具体如何判断某个字母是不是第一次出现,待会儿可以看下源码,很容易理解,这里就不贴代码了。

5.实现点击右侧字母,联系人自动移到对应联系人

其实和中间的正方形显示字幕一个意思,同样是在回调里面实现,回掉里面拿到字幕Word,然后遍历persons,如果person拼音的首位与word相同,那么记录下位置i,然后移动就可以了,主要代码如下:


    private void getWord(String word) {

        for (int i = 0; i < persons.size(); i++) {
            String substring = persons.get(i).getPinyin().substring(0, 1);
            if (substring.equals(word) && persons.size() >= i) {
                //如果person拼音的首位与word相同,则实现效果,并退出循环
                View childAt = rvMain.getChildAt(i);
                MoveToPosition(linearmanger, rvMain, i);
                break;
            }
        }
    }

    /**
     * 此方法是让recycleview滑动到指定位置,并且是让其到顶部
     *
     * @param manager
     * @param mRecyclerView
     * @param n
     */
    public void MoveToPosition(LinearLayoutManager manager, RecyclerView mRecyclerView, int n) {
        int firstItem = manager.findFirstVisibleItemPosition();
        int lastItem = manager.findLastVisibleItemPosition();
        if (n <= firstItem) {
            mRecyclerView.scrollToPosition(n);
        } else if (n <= lastItem) {
            int top = mRecyclerView.getChildAt(n - firstItem).getTop();
            mRecyclerView.scrollBy(0, top);
        } else {
            mRecyclerView.scrollToPosi
tion(n);
        }
    }

这样就简单实现了联系人快速定位的功能,有问题请加QQ群661614986,点击查看源码

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值