美文网首页AndroidAndroid 自定义viewView
Android Canvas 实现抽屉动画和翻滚动画

Android Canvas 实现抽屉动画和翻滚动画

作者: 徐正峰 | 来源:发表于2017-08-01 20:48 被阅读639次

需求

在开发中,有这样的需求,view在某种操作下会有抽屉的展示,而且里面的文字会有翻滚的效果,如下:



即列表向上滑动时,旁边的气泡会折叠(并未折叠所有),向下滑动时,气泡会展开,当有新内容时,里面的文字内容会翻滚显示。

实现

所有的效果都是通过Canvans来实现,也是希望借该博客来和大家来分享一下,当开发时视觉需要实现某些动画效果时,第一想到的不是通过Google去搜索别人的实现,然后去套用,而是沉下心来去思考,去分解动画,然后通过Canvas去实现,当你这样做以后,你会发现实际上并非这么难,才能以不变应万变。这样当需求改变时,才能很快的解决。

抽屉效果

  • 分解展开动画


    �上图可以看出,动画从第一幅图到最后一幅图右边的圆角是不变的,这时候很容易就有思路,假设整个动画的持续时间是500ms,我们只需要在500ms之内匀速�绘制一个半圆角矩形就可以了。

  • 代码实现

    绘制初始化圆角矩形

    
    private void drawView(Canvas canvas) {
       mDrawPath.reset();
       mDrawPath.addRoundRect(mExpandViewRect, mRadiusRectF, Path.Direction.CW);
       canvas.drawPath(mDrawPath, mBorderPaint);
       //绘制背景
       mDrawPath.reset();
       mDrawPath.addRoundRect(mExpandViewRect, mRadiusRectF, Path.Direction.CW);
       canvas.drawPath(mDrawPath, mBackPaint);
    }
    
    

    我们通过Path来绘制半圆角矩形,每个角的角度可以自己设置。如下代码:

    
    public void setRadius(float leftTop, float rightTop, float rightBottom, float leftBottom) {
        mRadiusRectF[0] = leftTop;
        mRadiusRectF[1] = leftTop;
        mRadiusRectF[2] = rightTop;
        mRadiusRectF[3] = rightTop;
        mRadiusRectF[4] = rightBottom;
        mRadiusRectF[5] = rightBottom;
        mRadiusRectF[6] = leftBottom;
        mRadiusRectF[7] = leftBottom;
    }
    
    

    当外界触发展开操作时,设置当前状态为从展开到折叠,然后在onDraw函数里进行绘制,如果设置动画时间为500ms。

    
    private void drawExpand2CollapseView(Canvas canvas) {
        float ratio = getAnimRatio();
        float distance = mExpandOrCollapseDistance * ratio;
        int left = (int) (mBorderWidth + distance);
    
        mExpandViewRect.set(left, mExpandViewRect.top, mExpandViewRect.right, mExpandViewRect.bottom);
        drawView(canvas);
        drawCollapseText(canvas);
        if (ratio == 1) {
            mCurrentStatus = STATUS_COLLAPSE;
        } else {
            invalidate();
        }
    }
    
    private float getAnimRatio() {
        long now = System.currentTimeMillis();
        float ratio = (now - mStartTime) / mDrawerAnimDuration;
        return ratio >= 1 ? 1 : ratio;
    }
    
    

    其中mStartTime是触发展开操作的起始时间,通过当前时间和起始时间的差值再来除以动画持续的时间,得到当前的比例,再把比例乘以需要伸缩的那部分距离,就得到当前绘制的长度,如果比例为1,则证明时间用完,动画结束。大体的思路是这个样子。

文字在这个过程中怎么处理,完全随着自己业务需要而修改,比方说字体平移,字体变大都可以,只需要拿到这个比例算出值,然后通过canvas来绘制即可,非常方便

翻转效果

android里面的翻转效果很多童鞋会想到用TextSwitcher来实现,但是在这种场景下是做不了的,因为首先这个view是一个圆角矩形,如果把他作为TextSwitcher的子view来进行翻转,会发现有圆角哪一侧有很显然的漏洞,�如下如所示:



所以还是得用Canvas来实现这个动效,视觉要求,当有新内容来时,里面的文字垂直滚动即可。

  • 分解滚动动画

    当下一个文字来时,上一个文字向上平移并且透明度变小,新来的文字慢慢平移到中间,并且透明度变大。知道了这么多,代码写起来就得心应手了。下面截下关键代码:

  • 实现

    
    private void drawNextTextView(Canvas canvas) {
        drawExpandBack(canvas);
    
        float ratio = getNextTextRatio();
        String text;
        Rect bounds;
        Paint.FontMetricsInt fontMetrics = null;
        int baseline;
        float start;
        if (ratio != 1) {
            bounds = new Rect();
            mTextPaint.getTextBounds(mCurrentText, 0, mCurrentText.length(), bounds);
            start = mExpandViewRect.left + mLeftTopRectRadius * 0.8f + (mExpandViewRect.width() - mLeftTopRectRadius - bounds.width()) / 2;
            fontMetrics = mTextPaint.getFontMetricsInt();
            baseline = (int) ((mHeight * (1 - ratio) - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top);
    
            mTextPaint.setAlpha((int) (255 *  (1 - ratio)));
            canvas.drawText(mCurrentText, start, baseline, mTextPaint);
    
            bounds = new Rect();
            mTextPaint.getTextBounds(mNextText, 0, mNextText.length(), bounds);
            start = mExpandViewRect.left + mLeftTopRectRadius * 0.8f + (mExpandViewRect.width() - mLeftTopRectRadius - bounds.width()) / 2;
            baseline = (int) (((mHeight - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top) + mHeight / 2 * (1 - ratio));
    
            mTextPaint.setAlpha((int) (255 * ratio));
            canvas.drawText(mNextText, start, baseline, mTextPaint);
    
            postInvalidateDelayed(50);
        } else {
            mTextPaint.setAlpha(255);
            bounds = new Rect();
            mTextPaint.getTextBounds(mNextText, 0, mNextText.length(), bounds);
            fontMetrics = mTextPaint.getFontMetricsInt();
            start = mExpandViewRect.left + mLeftTopRectRadius * 0.8f + (mExpandViewRect.width() - mLeftTopRectRadius - bounds.width()) / 2;
            baseline = ((mHeight - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top);
    
            canvas.drawText(mNextText, start, baseline, mTextPaint);
    
            String text1 = mNextText;
            mNextText = mCurrentText;
            mCurrentText = text1;
        }
    }
    
    

    基本思路也是设置一个动画时间,算出当前变化的比例,通过Canvas来不停的绘制文字达到滚动的效果。如果说需要有更立体的效果,比方说翻滚的过程中字体大小也需要改变,按照这样的思路,设置paint的textsize�即可。

好,今天的分享就到这里。这里贴出这个效果的 Github Demo地址。�里面还有其他动画哟,多多支持,点个赞哈。

相关文章

  • Android Canvas 实现抽屉动画和翻滚动画

    需求 在开发中,有这样的需求,view在某种操作下会有抽屉的展示,而且里面的文字会有翻滚的效果,如下: 即列表向上...

  • 动画

    Android中的动画主要分为补间动画、帧动画和属性动画。 1.补间动画与帧动画都是canvas对matrix的操...

  • Android源码相关分析(a)

    1、Android动画框架实现原理 android 动画框架分为三种类别:渐变动画、帧动画、属性动画Android...

  • Android 动画锦集

    Android 动画可分为逐帧动画、补间动画、属性动画。使用传统的逐帧动画、补间动画可以实现 Android 基本...

  • Android动画技术分析

    本文将介绍Android动画的实现技术。Android动画实现有三种技术,逐帧动画(Drawable Animat...

  • Android 属性动画拓展(一)

    Android 属性动画拓展(一) 前言 通过之前Android动画总结一文,我们对Android开发中的动画实现...

  • Android动画详解

    Android动画分类 Android动画分为传统动画和属性动画(Android3.0之后引入) 传统动画 帧动画...

  • 2018-08-22

    动画技术向 canvas动画,是AN可以输出的吗?json文件又是属于什么动画的?和canvas是不同的格式的吧?

  • Android-UI控件

    手摸手教你写 Slack 的 Loading 动画 四步实现:画布旋转及线条变化动画(Canvas Rotate ...

  • 动画UI总结

    1.Android 从 json 文件到炫酷动画 - Lottie 实现思路和源码分析2.Android酷炫动画是...

网友评论

本文标题:Android Canvas 实现抽屉动画和翻滚动画

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