web-dev-qa-db-ja.com

ビューの翻訳をアニメーション化する方法

ボタンの最初のクリックで、Viewをx軸に沿ってスライドさせます(たとえば200ピクセル右に移動します)。ボタンを2回押すと、Viewをx軸に沿って元の位置にスライドさせて戻します。

View.setTranslationX(float)メソッドjumpsそれぞれmyView.setTranslationX(200);およびmyView.setTranslationX(0);を呼び出して、ターゲットの水平位置にビューをジャンプします。代わりにターゲットの水平位置にViewslideする方法を知っている人はいますか?

注1:TranslateAnimationは実際にはViewを移動せず、動いているように見えるだけなので、ダメです。

注2:setTranslationX(float)およびsetTranslationY(float)メソッドがAPIレベル11の時点で導入されたという質問を投げかけたとき、私は気づきませんでした。 Honeycomb(API Level 11)を上方にターゲットする場合、Gautam Kの答えで十分です。それ以外の場合は、推奨される解決策についての私の答えを参照してください。

21
Adil Hussain

これはかなりの数日間困惑しました(アイスクリームサンドイッチの前にそれを動作させる)が、私はついにそこに着いたと思います! (リードしてくれたGautam KとMike Israelに感謝します)最後にやったのは、必要に応じてView(a FrameLayout)を拡張して、右/左アニメーションの翻訳を開始し、聞くことでした次のように、必要に応じてFrameLayoutを右/左に再配置するために、アニメーションの最後に:

_public class SlidingFrameLayout extends FrameLayout
{
  private final int durationMilliseconds = 1000;
  private final int displacementPixels = 200;

  private boolean isInOriginalPosition = true;
  private boolean isSliding = false;

  public SlidingFrameLayout(Context context)
  {
    super(context);
  }

  public SlidingFrameLayout(Context context, AttributeSet attrs)
  {
    super(context, attrs);
  }

  public SlidingFrameLayout(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs, defStyle);
  }

  @Override
  protected void onAnimationEnd()
  {
    super.onAnimationEnd();

    if (isInOriginalPosition)
      offsetLeftAndRight(displacementPixels);
    else
      offsetLeftAndRight(-displacementPixels);

    isSliding = false;
    isInOriginalPosition = !isInOriginalPosition;
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom)
  {
    super.onLayout(changed, left, top, right, bottom);

    // need this since otherwise this View jumps back to its original position
    // ignoring its displacement
    // when (re-)doing layout, e.g. when a fragment transaction is committed
    if (changed && !isInOriginalPosition)
      offsetLeftAndRight(displacementPixels);
  }

  public void toggleSlide()
  {
    // check whether frame layout is already sliding
    if (isSliding)
      return; // ignore request to slide

    if (isInOriginalPosition)
      startAnimation(new SlideRightAnimation());
    else
      startAnimation(new SlideLeftAnimation());

    isSliding = true;
  }

  private class SlideRightAnimation extends TranslateAnimation
  {
    public SlideRightAnimation()
    {
      super(
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, displacementPixels,
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, 0);

      setDuration(durationMilliseconds);
      setFillAfter(false);
    }
  }

  private class SlideLeftAnimation extends TranslateAnimation
  {
    public SlideLeftAnimation()
    {
      super(
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, -displacementPixels,
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, 0);

      setDuration(durationMilliseconds);
      setFillAfter(false);
    }
  }
}
_

最後に、SlidingFrameLayoutを左右にスライドするには、SlidingFrameLayout.toggleSlide()メソッドを呼び出すだけです。もちろん、このSlidingFrameLayoutを微調整して、より多くのピクセルをスライドさせたり、より長くスライドさせたりすることもできますが、これで十分です:)

5
Adil Hussain

ObjectAnimator とそのスーパークラスValue Animatorを調べてみてください

このようなObjectAnimator anim = ObjectAnimator.ofFloat(this, "translationX", 0,200);を実行してから、anim.start();

boolean値を使用し、オブジェクトアニメーターで200,0で切り替えてスライドバックします

PS:setDurationメソッドを使用して、アニメーションの完了に要する時間を設定できます

編集:

後方互換性を提供する support library を見てみてください。

編集

@AdilHussainが指摘したように、 nineoldandroids と呼ばれるライブラリがあり、これは古いAndroidでも同じ目的に使用できます。

26
Gautam

同様の問題がありました。setFillAfterを呼び出すと、TranslateAnimationは実際にビューを移動します( Androidのバグ )。似たようなことをしなければならなかったので、アニメーションリスナを使用して、すべてを正しい場所に移動させます。残念ながら、アニメーションリスナーにもバグがあります( stackoverflow solution )。 stackoverflow solution のソリューションに従って、独自のレイアウトクラスを作成しました。

2
MikeIsrael