繁体   English   中英

具有自定义视图的旋转动画

[英]Rotation animation with custom view

我有一个自定义的View,IndicatorView,它本质上是一个三角形,它根据半径等于三角形长度的圆的指定角度对自身进行定向。 三角形指向的角度经常更新,我想在这两个位置之间设置动画,类似于时钟上的指针如何移动。 以下是我的自定义视图的图示(未按比例绘制或按比例绘制;根据Android View坐标平面绘制):

在此处输入图片说明

在IndicatorView类中,我使用Path对象和三个PointF对象绘制三角形:

@Override
protected void onDraw(Canvas canvas){
    path = new Path();
    path.setFillType(Path.FillType.EVEN_ODD);
    //a, b, and c are PointF objects
    path.moveTo(a.x, a.y);
    path.lineTo(b.x, b.y);
    path.lineTo(c.x, c.y);
    path.close();
    canvas.drawPath(path, paint);
}

为了计算给定角度的不同点,我使用参数方程式:

public void showAngle(){
    //x = centerX + radius * cos(angle)
    //y = centerY + radius * sin(angle)
    //TODO sloppy; tidy up / optimize once finished
    //centerX, centerY, length, and bottomWidth are all values
    //calculated in onSizeChanged
    a = new PointF((float) (centerX + (length * Math.cos(angle))), (float) (centerY + (length * Math.sin(angle))));
    //perpendicular bilateral radius
    double pRadius = bottomWidth / 2;
    //perpendicular angle plus or minus 90 degrees depending on point
    float pAngle = angle - 90;
    pAngle = (pAngle < 0) ? 360 - Math.abs(pAngle) : pAngle;
    pAngle = (pAngle > 360) ? pAngle % 360 : pAngle;
    b = new PointF((float) (centerX + (pRadius * Math.cos(pAngle))), (float) (centerY + (pRadius * Math.sin(pAngle))));
    pAngle = angle + 90;
    pAngle = (pAngle < 0) ? 360 - Math.abs(pAngle) : pAngle;
    pAngle = (pAngle > 360) ? pAngle % 360 : pAngle;
    c = new PointF((float) (centerX + (pRadius * Math.cos(pAngle))), (float) (centerY + pRadius * Math.sin(pAngle)));
    invalidate();
}

当我有一个新角度时,我使用ObjectAnimator在两个角度之间设置动画。 我将AnimatorUpdateListener放在ObjectAnimator上,并使用从Animator指定的中间值在我的IndicatorView中调用showAngle()方法:

public void updateAngle(float newAngle){
    //don't animate to an angle if the previous angle is the same
    if(view.getAngle() != newAngle){
        if(anim != null && anim.isRunning()){
            anim.cancel();
        }
        anim = ObjectAnimator.ofFloat(view, "angle", view.getAngle(), newAngle);
        anim.setDuration(duration);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                if(view != null){
                    view.showAngle();
                }
            }
        });
    }
}

但是,此代码会产生一些奇怪的意外行为:

  • 三角形的宽度大小会急剧变化。 这可能是由于不同类型之间的转换引起的,但不应该那么引人注目。
  • 三角形的点永远不会停在指定的角度。 相反,它只是绕圈运动。
  • 角度似乎决定了动画的速度,而不是三角形应停在的位置。
  • 有时似乎屏幕上有许多三角形。 这可能是由于速度所致,也许是移动速度非常快。

显然,尽管如此,我的计算肯定是不正确的,但我一直在努力找出哪里出了问题。 问题:是否有更有效的方法来使我的自定义视图对旋转到给定角度进行动画处理? 如果我正确地解决了这个问题,那我哪里出错了?

因此,解决我的问题的方法相当简单,但又足够容易被忽略。 计算中使用的角度场以度为单位,只需将其转换为弧度即可使用sin和cos方法。

更改所有PointF实例,例如:

a = new PointF((float) (centerX + (length * Math.cos(angle))), (float) (centerY + (length * Math.sin(angle))));

使用弧度角:

a = new PointF((float) (centerX + (length * Math.cos(Math.toRadians(angle))),
        (float) (centerY + (length * Math.sin(Math.toRadians(angle)))));

另外,部分问题是由于不断分析声音并在上一个动画有时间渲染几帧之前更新了视图。 这导致在频繁更新角度时,IndicatorView几乎不动,而在不更新角度时,它会迅速移至其目的地。 发生这种情况是因为在设置另一个动画之前,先前的动画被取消了(这是防止延迟的必要步骤)。 这是一个棘手的问题,但是我发现一个优化是避免在当前角度和前一个角度相对接近的情况下避免启动新动画。

希望这对遇到类似问题的人有用。 这是我正在从事的吉他调音器项目的全部内容,其源代码可以在GitHub找到

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM