22

だから私はアニメーションを使ってビューをアニメーション化しています:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="1000"
        android:fromYDelta="0%"
        android:toYDelta="-75%" />

</set>

それは私が望むことを視覚的に行いますが、このアニメーションの結果をフリーズしたいです。アニメーションの後に結果のレイアウトパラメータ(または何か他のもの?)を取得してレイアウトに設定する必要があるように。レイアウトの Y 座標が 0 から 100 に変化すると仮定しますが、何が開始座標で、何が結果座標であるかはよくわかりません。結果の座標を取得し、それをレイアウト cuz に設定する必要があります。 そうしないと、アニメーション後にレイアウトが元の位置に戻りますが、元に戻るのではなく、新しい位置にとどまるようにする必要があります。また、2.3.x 互換のソリューションが必要です。
更新 1
私も NineOldAndroids を試しました:

ObjectAnimator.ofFloat(rootWrapper, "translationY", -rootWrapper.getHeight()*75/100).start();

これはビューをアニメーション化し、ビューはアニメーション化された位置にとどまります-それはまさに私が達成したいことです。
ただし、すべてのコントロールは事実上その位置にとどまります。その空の画面領域をタップすると、レイアウトが下部の 25% しか表示されず、残りの画面の 75% が空に見えます。設定されている場合、xml-animtaions でも同じことが起こります

animation.setFillAfter(true); 

その問題を解決するにはどうすればよいですか?すべてのコントロールは、ビューと共に移動する必要があります。
UPDATE 2
コード:

    public void showAbout(){

        final Animation animShow = AnimationUtils.loadAnimation(this, R.anim.about_in_from_bottom);
        animShow.setFillAfter(true); 

        //ObjectAnimator.ofFloat(rootWrapper, "translationY", -rootWrapper.getHeight()*75/100).start();

        animShow.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                LinearLayout.LayoutParams rootlp = (LinearLayout.LayoutParams) rootWrapper.getLayoutParams();
                Log.i(this,"rootlp: h: "+rootlp.topMargin+ " / w: "+rootlp.bottomMargin);
                rootlp.topMargin = -rootlp.height*75/100;
                rootWrapper.setLayoutParams(rootlp);
            }
        });

        rootWrapper.startAnimation(animShow);
    }

問題が発生しましたrootlp.height-MATCH_PARENTなどのように0 cuzを返します。REAL ピクセルは返されませんが、定数を表す値が返されます。だから、私は で 2 プレイしているよう.getViewTreeObserver().addOnGlobalLayoutListenerです。
わかりました、getViewTreeObserver() を介して rootWrapper の実際の高さを取得しました。そして今、式rootlp.topMargin = -rootlp.height*75/100;を使用すると、さらに多くの問題が発生します。
1) アニメーション後、ビューがさらに上に移動します (LP の設定による)。
2) アニメーション ビューに含まれるコントロール (親ビューと共に上に移動する必要があるボタン) は、仮想的にその位置にとどまります (非表示ですがクリック可能です)。これらのコントロールは、アニメーション化されたビューで視覚的に上に移動し、到達できません (画面から消えます)。しかし、アニメーションに対応する onClick() トリガーの前にあった領域をタップすると! なんて楽しい!
更新 3
ついに目標を達成しました!問題は、ビューの子コンテナーの移動にありました。ビューを移動すると、そのすべての子ビューも移動すると考えていました。しかし、そうではなく、アニメーションが完了した後、子ビューを手動で移動してゴースト ボタンを修正する必要がありました。

4

3 に答える 3

54

setFillAfter(boolean); を検討してください。true に設定すると、ビューはアニメーションの位置にとどまります。

Animation anim = new TranslateAnimation(0, 0, 0, 100);

// or like this
Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation_name);

anim.setFillAfter(true); 
anim.setDuration(1000);

これは、API 14 以降で利用可能なViewPropertyAnimatorを使用してさらに簡単に行うことができます。

int animationpos = 500;
View.animate().y(animationpos).setDuration(1000); // this will also keep the view at the animated position

または、AnimationListenerを使用して、アニメーションの直後に LayoutParams を取得することを検討してください。

anim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {}

            @Override
            public void onAnimationRepeat(Animation animation) {}

            @Override
            public void onAnimationEnd(Animation animation) {
                  // get layoutparams here and set it in this example your views 
                  // parent is a relative layout, please change that to your desires

                  RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) View.getLayoutParams();
                  lp.topMargin = yournewtopmargin // use topmargin for the y-property, left margin for the x-property of your view
                  View.setLayoutParams(lp);
                }
            });

    View.startAnimation(anim);

アップデート:

アニメーションのパーセンテージ値に応じて、ビューが移動したピクセル数を知る方法は?

.xml アニメーションのパーセンテージ値は、アニメーション化されたビューの寸法 (幅や高さなど) に相対的です。したがって、ビューの幅と高さのプロパティを使用するだけで済みます(天候に応じて、x または y アニメーションを使用して実際のアニメーション距離をピクセル単位で取得します)。

例えば:

ビューの幅は 400 ピクセルです。アニメーションは x プロパティを 0% から 75% までアニメーション化します。つまり、ビューは 300 ピクセル (400 * 0.75) 右側に移動します。したがって、onAnimationEnd() で LayoutParams.leftMargin を 300 に設定すると、ビューが目的の位置になります。

于 2013-08-16T08:55:25.730 に答える
2

クリック/タッチリスナーなどが関係している場合、fillEnabled と fillAfter を TRUE に設定するだけでは問題が解決しないことがわかりました。fill enabled と fill after を true に設定すると、ビューのピクセルが正しい最終的な場所に描画されるようになります。ただし、アニメーション化されているビューに onclick リスナーが関連付けられているとします。新しい表示位置でビューをクリックしても何も起こりませんが、ビューが元々あった位置で画面をクリックすると onClick がトリガーされます。

以下は、これを回避する方法の例です。

onClickListener が設定されたビューがあるとします。また、ビューの境界が 0、0、0、0 (左、上、右、下) であるとします。ここで、ビューを 200 だけ右に移動したいとします。次のコードは、描画されるピクセルと下にあるビュー オブジェクトの両方を正しい位置に移動する方法でこれを行う方法を示しています。したがって、onClick を次のように調整します。正しい位置からコールされます。

private Animation generateMoveRightAnimation() {
    final Animation animation = new TranslateAnimation(Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 200,
            Animation.ABSOLUTE, 0, Animation.ABSOLUTE, 0);
    animation.setDuration(300);
    animation.setFillAfter(true);
    animation.setFillEnabled(true);

    animation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) view.getLayoutParams();
            // change the coordinates of the view object itself so that on click listener reacts to new position
            view.layout(view.getLeft()+200, view.getTop(), view.getRight()+200, view.getBottom());
            repeatLevelSwitch.clearAnimation();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

    return animation;
}
于 2015-07-06T15:40:03.673 に答える