美文网首页
自定义控件实践-带特效的索引栏

自定义控件实践-带特效的索引栏

作者: Zhang_min | 来源:发表于2017-11-06 20:52 被阅读0次

效果预览

jdfw.gif

前言

上一段时候面试了一些人, 问到通讯录中侧边的快速索引这个怎么实现. 没想到好几个人都回答不上来, 看到他们简历上写的熟悉掌握自定义控件 (汗 ==!) . 想到以前写的带特效的快速索引栏, 点击的时候该区域就会弹起,效果还是不错的。 下面一步步分析应该怎么实现这个控件。

分析需求

自定义控件先看分析静态的。a~z 怎么绘制呢~ 有的人居然回答是用ListView来做... ((⊙o⊙)) . 因为a~z是要在一个地方绘制的. 不是什么列表. 所以应该想到用是用canvas.drawText()方法. 还有这个应该是继承View而不是ViewGroup.因为a~z是在一个View上的.

静态view分析实现.

最关键的api是canvas.drawText(letter, x, y, paint); 这个方法可以指定绘制什么. 同时可以指定绘制的位置.可以知道这些字母绘制的时候横坐标应该不变化. 变化的是纵坐标. 而且纵坐标.是有规律的变化

动态view分析实现

所谓的动态就是 点击的时候这个区域内的字母要向左偏移. 并且相邻的代码要也要有不同程度的左偏移. 点击的时候应该去考虑在onTouchEvent中获取x y坐标 ,通过坐标去判断哪个字母应该做什么效果. 当放手的时候 这个已经偏移的view不会立马恢复到初始状态. 而是要有一定时间. 这个怎么实现呢~ 有两种思路 .
第一: 通过当Scroller这个类去模拟数据变化. 这个一般用的少.我用这种写法 巩固一下基础~~
还有一种思路 就是利用属性动画.指定值的属性 然后也可以得到一定时间内变化的值~

关键的代码

绘制onDraw();

 @Override
    protected void onDraw(Canvas canvas) {
        // 遍历26个英文字母, 计算坐标, 进行绘制
        for (int i = 0; i < LETTERS.length; i++) {
            String letter = LETTERS[i];

            // 计算x坐标
            float dx = 0;
            //float x = cellWidth * 0.5f - paint.measureText(letter) * 0.5f + 80;
            //  float x = cellWidth - paint.measureText(letter);
            float x = cellWidth - measureText * 1.5f;
            if (!isUp) {
                mX = 1.0f;
            }
            switch (currentIndex - i) {
                case -4:
                    dx = measureText * 1.5f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_4));
                    setTextSize(27);
                    break;
                case -3:
                    dx = measureText * 2.5f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_3));
                    setTextSize(33);
                    break;
                case -2:
                    dx = measureText * 4.0f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_2));
                    setTextSize(38);
                    break;
                case -1:
                    dx = measureText * 5.0f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_1));
                    setTextSize(42);
                    break;
                case 0:
                    paint.setColor(getResources().getColor(R.color.text_blue_search));
                    dx = measureText * 6.0f * mX;
                    setTextSize(50);
                    break;
                case 1:
                    dx = measureText * 5.0f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_1));
                    setTextSize(42);
                    break;
                case 2:
                    dx = measureText * 4.0f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_2));
                    setTextSize(38);
                    break;
                case 3:
                    dx = measureText * 2.5f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_2));
                    setTextSize(33);
                    break;
                case 4:
                    dx = measureText * 1.5f * mX;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_3));
                    setTextSize(28);
                    break;
                default:
                    dx = 0;
                    paint.setColor(getResources().getColor(R.color.text_blue_search_4));
                    setTextSize(26);
                    break;
            }
            if (!isUp) { //触摸状态
                x -= dx;
            } else {  //松手状态
                x -= dx;
                paint.setColor(getResources().getColor(R.color.text_blue_search));
                setTextSize(26);
            }

            // 计算y坐标
            Rect bounds = new Rect();
            // 获取文本的矩形区域
            paint.getTextBounds(letter, 0, letter.length(), bounds);
            float y = cellHeight * 0.5f + bounds.height() * 0.5f + i * cellHeight;

            // 绘制文本
            if (letter.equals("I")) {
                x += measureText * 0.2f;
            }
            canvas.drawText(letter, x, y, paint);
        }
    }

处理点击的操作:

 @Override
    public boolean onTouchEvent(MotionEvent event) {

        float y;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                scroller.forceFinished(true);
                isUp = false;
                setPadding(500, 0, 0, 0);
                // 获取被点击到的字母索引
                y = event.getY();
                // 根据y值, 计算当前按下的字母位置
                currentIndex = (int) (y / cellHeight);
                if (currentIndex != lastIndex) {
                    if (currentIndex >= 0 && currentIndex < LETTERS.length) {
                        String letter = LETTERS[currentIndex];
                        if (onLetterUpdateListener != null) {
                            onLetterUpdateListener.onLetterUpdate(letter);
                        }
                        // 记录上一次触摸的字母
                        lastIndex = currentIndex;
                    }
                }

                break;
            case MotionEvent.ACTION_MOVE:
                // 获取被点击到的字母索引
                y = event.getY();
                // 根据y值, 计算当前按下的字母位置
                currentIndex = (int) (y / cellHeight);
                if (currentIndex != lastIndex) {
                    if (currentIndex >= 0 && currentIndex < LETTERS.length) {
                        String letter = LETTERS[currentIndex];
                        if (onLetterUpdateListener != null) {
                            onLetterUpdateListener.onLetterUpdate(letter);
                        }
                        // 记录上一次触摸的字母
                        lastIndex = currentIndex;
                    }
                }

                break;
            case MotionEvent.ACTION_UP:
                isUp = true;
                lastIndex = -1;
                //调用回调里面的方法
                if (null != onUpListener) {
                    onUpListener.up();
                }
                smaooth();

                break;
            default:
                break;
        }
        invalidate();
        return true;
    }

总结:

自定义控件其实不难 看到需求之后, 先别忙着写. 先好好分析应该怎么实现是最高简洁的. 然后先实现静态的view 然后再考虑动态的变化. 分析清楚了, 代码就好写了.~~
最后奉上Demo地址: https://github.com/zmin666/QuickIndexBar
如果对你有帮助, 欢迎star~~

相关文章

  • 自定义控件实践-带特效的索引栏

    效果预览 前言 上一段时候面试了一些人, 问到通讯录中侧边的快速索引这个怎么实现. 没想到好几个人都回答不上来,...

  • Android面试准备

    一、简历准备 1、个人技能 (1)自定义控件、UI设计、常用动画特效 自定义控件 ①为什么要自定义控件? Andr...

  • QT2

    1、带菜单栏的窗口2、资源文件3、对话框4、界面布局5、常用控件6、自定义控件 1QMainWindow1.1菜单...

  • Android面试复习-View

    自定义控件 1.组合控件。这种自定义控件不需要我们自己绘制,而是使用原生控件组合成新控件,如标题栏。 2.继承原有...

  • 动画

    Android自定义控件三部曲文章索引

  • Android自定义标题栏控件(补充)

    在上一篇文章Android 自定义复合控件之通用标题栏中记录了自定义标题栏控件的整个过程,不过如果直接拿来在别的项...

  • 自定义简单字母索引栏

    说到字母索引栏,在联系人模块经常会见到。iOS中这种控件是自带的,安卓中是没有的,所以只能自定义解决了。 需求分析...

  • 自定义简单字母索引栏

    说到字母索引栏,在联系人模块经常会见到。iOS中这种控件是自带的,安卓中是没有的,所以只能自定义解决了。 需求分析...

  • 关于自定义控件的博客收藏

    Android自定义控件:带你掌握一款多特效的智能loadingView:https://www.jianshu....

  • ObjectAnimator基本使用

    Android自定义控件三部曲文章索引 ObjectAnimator基本使用

网友评论

      本文标题:自定义控件实践-带特效的索引栏

      本文链接:https://www.haomeiwen.com/subject/rekrmxtx.html