簡體   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