Android - 高仿Morning Routine中的PagerIndicator之动画实现

Android - Animation 贝塞尔曲线之美中提到了PagerIndicator的绘制,这篇博客继续分析下动画应该如何实现。

Property Animation 分析

顾名思义,要实现属性动画,首先要对属性进行分析,然后对动画做分析。

属性分析

在这个PagerIndicator动画中,我们可以看出有两个圆,就有圆的坐标点半径这两个属性,还有颜色的变化,所以颜色也是个属性。

动画分析

在这个PagerIndicator动画中,我们可以知道两个圆的动画起点和终点都是一样的,要实现这样一前一后的效果,肯定一个圆是加速,一个圆是减速,所以我们要使用的AccelerateInterpolatorDecelerateInterpolator这两个插值器。

代码实现

  • 定义属性,并生成seter和geter

    1
    2
    3
    4
    private float leftCircleRadius;
    private float leftCircleX;
    private float rightCircleRadius;
    private float rightCircleX;
  • 确定圆形的位置

    1
    2
    3
    4
    for (int i = 0; i < mPagerCount; i++) {
    int x = mWidth / (mPagerCount + 1) * (i + 1);
    mPoints.add(new PointF(x, 0));
    }
  • 定义圆的运动动画

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    float leftX = mPoints.get(left).x;
    float rightX = mPoints.get(right).x;
    // 右边的圆初始速度快,做减速运动
    ObjectAnimator rightPointAnimator = ObjectAnimator.ofFloat(this, "rightCircleX", leftX, rightX);
    rightPointAnimator.setDuration(5000L);
    rightPointAnimator.setInterpolator(new DecelerateInterpolator());
    mAnimators.add(rightPointAnimator);
    // 左边的圆初始速度慢,做加速运动
    ObjectAnimator leftPointAnimator = ObjectAnimator.ofFloat(this, "leftCircleX", leftX, rightX);
    leftPointAnimator.setDuration(5000L);
    leftPointAnimator.setInterpolator(new AccelerateInterpolator());
    mAnimators.add(leftPointAnimator);
    // 右边的圆半径由小变大
    ObjectAnimator rightCircleRadiusAnimator = ObjectAnimator.ofFloat(this, "rightCircleRadius", mMinCircleRadius, mMaxCircleRadius);
    rightCircleRadiusAnimator.setDuration(5000L);
    rightCircleRadiusAnimator.setInterpolator(new AccelerateInterpolator());
    mAnimators.add(rightCircleRadiusAnimator);
    // 左边的圆半径由大变小
    ObjectAnimator leftCircleRadiusAnimator = ObjectAnimator.ofFloat(this, "leftCircleRadius", mMaxCircleRadius, mMinCircleRadius);
    leftCircleRadiusAnimator.setDuration(5000L);
    leftCircleRadiusAnimator.setInterpolator(new DecelerateInterpolator());
    mAnimators.add(leftCircleRadiusAnimator);
  • 定义颜色变化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    int color1 = mColors.get(left);
    int color2 = mColors.get(right);
    ValueAnimator paintColorAnimator = ObjectAnimator.ofInt(color1, color2);
    paintColorAnimator.setDuration(5000L);
    paintColorAnimator.setEvaluator(new ArgbEvaluator());
    paintColorAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
    paintColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    public void onAnimationUpdate(ValueAnimator animator) {
    mPaint.setColor((Integer) animator.getAnimatedValue());
    }
    });
  • 定位动画,因为动画是跟手动的,动画就不能一下子播出去,而是手动定位

    1
    2
    3
    for (ValueAnimator animator : mAnimators) {
    animator.setCurrentPlayTime((long) (5000.0F * offset));
    }
  • onPageChangeListener的回调

    1
    2
    3
    4
    5
    6
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    // position的值为viewpager的position,positionOffset的值是position到position+1的比例。
    // 换成人话是, 无论你滑动pager是0->1或者1->0,position的值都为0。
    indicator.setPositionAndOffset(position, positionOffset);
    }

至此动画就完成了

Gavin Liu wechat
欢迎您扫一扫上面的二维码,订阅我的微信公众号!