2011-12-01 50 views
2

我有一個應用程序,我需要根據當前聚焦的子視圖調整視圖位置(這是一個列表具有可聚焦項目,當前焦點項目必須在屏幕中心 - 用於電視應用程序從電視遙控器控制)。
位置必須用動畫調整。
我得到它只有一個問題:如果用戶在動畫完成之前改變焦點(快速點擊「向上」按鈕兩次)下一個動畫以「跳躍」開始 - 它從與第一個動畫相同的位置開始。中斷翻譯動畫,並開始另一個

所以我試圖做的是我取消以前的動畫並開始另一個動畫,但是隨後新動畫從第一個動畫開始的位置開始,所以用戶可以在動畫中看到非常明顯的跳躍,看起來非常糟糕。

下面的代碼:

@Override 
public void requestChildFocus(final View child, final View focused) { 
    super.requestChildFocus(child, focused); 

    //this test code included for explanation 
    Rect r = new Rect(); 
    child.getDrawingRect(r); //this will return view's position ignoring animation state 
    Rect r2 = new Rect(); 
    child.getGlobalVisibleRect(r2); //as will this one too 
    Log.d("Top: " + child.getTop() + "; Drawing rect: " + r.toString() + "; global visible rect: " + r2.toString()); 
    //all of this methods will ignore changes that were made 
    //by animation object - they'll return numbers from LayoutParam 

    //calculate current position inside view and position to move to 
    //cursorOffset - is the "center" of the screen 
    final int currentPosition = child.getTop(); 
    final int requaredPosition = cursorOffset - focused.getTop(); 

    //cancel current running animation - layout params will not change 
    //if i do change layout params when cancelling animation, it looks even worse 
    //because of jumping back list jumps forward 
    if (currentAnimation != null) { 
     Animation animation = currentAnimation; 
     currentAnimation = null; 
     animation.cancel(); 
    } 

    //just a regular translate animation 
    TranslateAnimation animation = new TranslateAnimation(0, 0, 0, requaredPosition - currentPosition); 
    animation.setDuration(300); 
    animation.setFillEnabled(true); 
    animation.setFillBefore(true); 
    animation.setAnimationListener(new AnimationListener() { 

     @Override 
     public void onAnimationStart(Animation animation) { 
      currentAnimation = animation; 
     } 

     @Override 
     public void onAnimationRepeat(Animation animation) {} 

     @Override 
     public void onAnimationEnd(Animation animation) { 
      if (animation == currentAnimation) { 
       //change layout params if animation finished running (wasn't cancelled) 
       RelativeLayout.LayoutParams params = (LayoutParams) child.getLayoutParams(); 
       params.setMargins(0, requaredPosition, 0, 0); 
       child.setLayoutParams(params); 
      } 
     } 
    }); 
    child.startAnimation(animation); 
} 

所以必須質疑的是:我怎麼能開始從以前的翻譯留在(假設它被取消)動畫點在哪裏翻譯動畫?
或者用簡單的話來說,我怎樣才能確定一個視圖的當前可見矩形?

回答

10

顯然你不能得到當前的視圖位置,但你可以得到當前的動畫狀態。
所以,你可以得到當前y通過這樣偏移:

Transformation transformation = new Transformation(); 
float[] matrix = new float[9]; 
currentAnimation.getTransformation(AnimationUtils.currentAnimationTimeMillis(), transformation); 
transformation.getMatrix().getValues(matrix); 
float y = matrix[Matrix.MTRANS_Y]; 

這就是我如何能夠從我離開的那一點恰好抵消一個動畫,並開始另一個。如果有人關心,繼承人的完整代碼:

private Animation currentAnimation; 
private float[] matrix = new float[9]; 
private Transformation transformation = new Transformation(); 

@Override 
public void requestChildFocus(final View child, final View focused) { 
    super.requestChildFocus(child, focused); 

    final int currentPosition; 

    if (currentAnimation != null) { 
     currentAnimation.getTransformation(AnimationUtils.currentAnimationTimeMillis(), transformation); 
     transformation.getMatrix().getValues(matrix); 
     float y = matrix[Matrix.MTRANS_Y]; 

     RelativeLayout.LayoutParams params = (LayoutParams) child.getLayoutParams(); 
     params.topMargin += y; 
     //child.getTop() will return wrong position until layout actually happens, 
     //so I use params.topMargin as a current position in case I need to cancel 
     currentPosition = params.topMargin; 
     child.requestLayout(); 

     currentAnimation.setAnimationListener(null); 
     currentAnimation.cancel(); 
     currentAnimation = null; 
    } else { 
     currentPosition = child.getTop(); 
    } 

    final int requaredPosition = cursorOffset - focused.getTop(); 

    TranslateAnimation animation = new TranslateAnimation(0, 0, 0, requaredPosition - currentPosition); 
    animation.setDuration(300); 
    animation.setFillEnabled(true); 
    animation.setFillBefore(true); 
    animation.setAnimationListener(new AnimationListener() { 

     @Override 
     public void onAnimationStart(Animation animation) { 
      currentAnimation = animation; 
     } 

     @Override 
     public void onAnimationRepeat(Animation animation) {} 

     @Override 
     public void onAnimationEnd(Animation animation) { 
      if (animation == currentAnimation) { 
       RelativeLayout.LayoutParams params = (LayoutParams) child.getLayoutParams(); 
       params.setMargins(0, requaredPosition, 0, 0); 
       child.requestLayout(); 
      } 
      currentAnimation = null; 
     } 
    }); 
    child.startAnimation(animation); 
} 

希望有人認爲這有用。

1

對於大家,搜索幫助創建一個時鐘或像我 速度計(尋找RotationAnimation < API拉特9), 我發現,這是設置AnimationListener並保存 動畫是個好主意狀態在一個布爾變量中。 開始新動畫之前,請檢查狀態。 所以你的動畫將運行到最後,看起來非常順利。 我很抱歉我的英語。

 if(isAnimationActive){ 
     //[...] 
     rotate = new RotateAnimation(oldRotateDegree, rotateDegree, Animation.RELATIVE_TO_SELF, 0.5f, 
          Animation.RELATIVE_TO_SELF, 0.5f); 
        rotate.setDuration(rotateDuration); 
        rotate.setFillAfter(true); 
        rotate.setAnimationListener(this); 
     }   
     //[...] 

     @Override 
     public void onAnimationEnd(Animation animation) 
     { 
      this.isAnimationActive = false; 

     } 
     @Override 
     public void onAnimationStart(Animation animation) 
     { 
      this.isAnimationActive = true; 
     }