55

アイテムのリストを含むアクティビティがあり、アイテムをクリックすると、そのアイテムの再生コントロールが画面の下部からスライドして表示されるようになります。スライドインとスライドアウトのアニメーションセットを定義しましたが、それらは機能します。アクティビティで animationListener をセットアップし、アイテムのアニメーション onClick でスライドを開始しました。私の問題は、アプリを初めて実行するとき、アイテムをクリックすると onClick コールバックが実行されますが、アニメーションは発生しません。2 回目にクリックすると、スライド イン アニメーションが発生しますが、スライド アウトは発生しません。3 回目以降は、期待どおりに動作します。これが私のアニメーションセットです。

vm_slide_in.xml

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
           android:fillAfter="true">
    <translate
        android:fromYDelta="800"
        android:toYDelta="0"
        android:duration="600" />
</set>

vm_slide_out.xml

    <?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" 
           android:fillAfter="true">
    <translate
        android:fromYDelta="0"
        android:toYDelta="800"
        android:duration="600" />
</set>

ここに私の活動のレイアウトがあります

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    style="@style/AppBG">
    <RelativeLayout 
        style="@style/LogoBar" 
        android:id="@+id/logo_bar"      
        android:layout_alignParentTop="true">
        <include layout="@layout/logobar"></include>
    </RelativeLayout>
    <RelativeLayout 
        style="@style/TitleBar" 
        android:id="@+id/title_bar"     
        android:layout_below="@+id/logo_bar">
        <include layout="@layout/titlebar"></include>"
        <Button style="@style/TitleBarButton"
            android:id="@+id/vm_speaker_btn"
            android:text="@string/vm_speaker_btn_label" 
            android:layout_alignParentLeft="true"
            android:layout_margin="4dp">
        </Button>
        <Button style="@style/TitleBarButton"
            android:id="@+id/vm_edit_btn"
            android:text="@string/vm_edit_btn_label" 
            android:layout_alignParentRight="true"
            android:layout_margin="4dp">
        </Button>
    </RelativeLayout>
    <ListView
        android:id="@+id/@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/title_bar"/>
    <RelativeLayout
        android:id="@+id/vm_control_panel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@+id/footer"
        android:visibility="gone">
        <include layout="@layout/vm_control"/>
    </RelativeLayout>
    <RelativeLayout
        android:id="@+id/footer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <include layout="@layout/taskbar"/>
    </RelativeLayout>
</RelativeLayout>

含まれているコントロールのレイアウトは次のとおりです

    <?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <RelativeLayout 
        android:id="@+id/vm_control"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@color/dark_grey">
        <TextView
            android:id="@+id/vm_ctl_branding"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dp"
            android:text="@string/branding"
            android:textColor="@color/white">
        </TextView>
        <TextView style="@style/TimeMark"
            android:id="@+id/vm_timestamp"
            android:layout_toLeftOf="@+id/vm_progress"
            android:layout_below="@+id/vm_ctl_branding"
            android:layout_marginRight="3dp"
            android:text="0:00">
        </TextView>
        <SeekBar
            android:id="@+id/vm_progress"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_below="@+id/vm_ctl_branding"
            android:layout_centerHorizontal="true">
        </SeekBar>
        <TextView style="@style/TimeMark"
            android:id="@+id/vm_timeleft"
            android:layout_toRightOf="@+id/vm_progress"
            android:layout_below="@+id/vm_ctl_branding"
            android:layout_marginLeft="3dp"
            android:text="-0:00">
        </TextView>
        <LinearLayout
            android:id="@+id/vm_action_button_layout"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignLeft="@+id/vm_timestamp"
            android:layout_alignRight="@+id/vm_timeleft"
            android:orientation="horizontal"
            android:layout_below="@+id/vm_progress">
            <TextView style="@style/Vm_Action_Button"
                android:background="@drawable/vm_action_btn_call"
                android:id="@+id/vm_callback_btn"
                android:layout_marginRight="5dp"
                android:text="@string/vm_action_btn_callback">
            </TextView>
            <TextView style="@style/Vm_Action_Button"
                android:background="@drawable/vm_action_btn_delete"
                android:id="@+id/vm_delete_btn"
                android:layout_marginLeft="5dp"
                android:text="@string/vm_action_btn_delete">
            </TextView>
        </LinearLayout>
    </RelativeLayout>
</merge>

私の onCreate メソッドから...

// Handle list item selections
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Voicemail vmItem = (Voicemail) vmla.getItem(position);
        Toast.makeText(ctx, "Name: " + vmItem.getCallerName() + " Position: " + position, Toast.LENGTH_SHORT)
                .show();
        vVm_controls.startAnimation(mSlideIn);
    }
});

そして私のアニメーションのコールバック...

@Override
public void onAnimationStart(Animation animation) {
    vm_controls_in = !vm_controls_in;
    if (vm_controls_in) {
        vVm_controls.setVisibility(View.GONE);
    } else {
        vVm_controls.setVisibility(View.VISIBLE);
        // vVm_controls.bringToFront();
    }
}

@Override
public void onAnimationEnd(Animation animation) {
    if (!vm_controls_in) {
        try {
            Thread.sleep(1000);
            vVm_controls.startAnimation(mSlideOut);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

@Override
public void onAnimationRepeat(Animation animation) {
    // TODO Auto-generated method stub

}
4

11 に答える 11

139

あなたが発見したように、問題は可視性です。ビューが最初に xml ファイルで削除されたように設定されている場合、Android は可視性が可視または不可視に変更されるまでレイアウトをレンダリングしません。まだレンダリングされていないビューでアニメーション化しようとすると、レイアウトのないビューでアニメーションが発生します。アニメーションが完了すると、アニメーションがレンダリングされ、突然ビューがアニメーションなしで表示されます。なくなった場合でもビューにレイアウトがあるため、それ以降は機能します。

重要なのは、可視性を xml ファイルに設定するのではなく、非表示に設定して、レンダリングされても非表示になるようにすることです。ビューが初めて表示され、期待どおりに移動するときにアニメーションが発生します。

于 2012-03-12T04:41:16.410 に答える
12

もちろん、この質問を投稿してから 20 分も経たないうちに、私は自分の問題を理解しました。レイアウトの可視性を「GONE」に設定していたので、アニメーションを開始しようとしたときに、初めてトリガーされませんでした。2回目以降は原因不明ですが、アニメーションを開始する直前に可視性を「VISIBLE」にすると問題は解決しました。これが私が変更したコードです...

// Handle list item selections
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Voicemail vmItem = (Voicemail) vmla.getItem(position);
        Toast.makeText(ctx, "Name: " + vmItem.getCallerName() + " Position: " + position, Toast.LENGTH_SHORT)
                .show();
        vVm_controls.setVisibility(View.VISIBLE);
        vVm_controls.startAnimation(mSlideIn);
    }
});
于 2010-12-21T19:43:17.793 に答える
3

現在の回答の多くは私にはうまくいきません。うまくいったのは を使用することだけでしonFocusWindowChange()たが、私はその解決策が好きではありません。

この問題を解決する私の方法: まず、xml レイアウトのviewようにアニメーション化しようとしている電流を設定します。invisible

次に、描画が終了onCreateしたときに通知するリスナーをレイアウトに追加します。view

mLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mLayout.setVisibility(View.GONE);
                mLayout.animate()
                        .translationX(-mLayout.getWidth());
                        
                mLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        });

レンダリングが終了した後、画面外に移動します

于 2021-01-03T11:39:06.800 に答える
2

Android 4.4.3 でも同様の問題がありました。提案された解決策のほとんどを試しましたが、うまくいった解決策は 1 つだけでした。ウィンドウのレンダリングが完了した後にアニメーションを実行する必要があり、最良の方法はonWindowFocusChanged内で実行することです。高速ハンドセットでのアプリケーションのパフォーマンスに影響を与えるため、runnable による遅延は使用しないでください。

@Override
public void onWindowFocusChanged (boolean hasFocus) {
   super.onWindowFocusChanged(hasFocus);
   if (hasFocus)
      yourView.startAnimation(anim);
}

詳細については、次の投稿を参照してください: https://damianflannery.wordpress.com/2011/06/08/start-animation-in-oncreate-or-onresume-on-android/

于 2016-08-12T00:16:39.160 に答える
0

私はまったく同じ問題を抱えていましたが、ViewPropertyAnimator. たとえば、GridView呼び出された を宣言しますmGridView。あなたが今しなければならないのはmGridView.animate()、あなたが望む変更を電話することだけです。

私のアニメーションGridViewがトリガーされましたが、不明な状況により、実際のアニメーションは表示されませんでした。また、すべてView.GONEView.VISIBLEに変更しましたが、何も変わりませんでした。私の場合android:requiresFadingEdge="vertical"、この特定の .xml の XMLを削除する必要があることがわかりましたGridView。Fading Edge と を組み合わせて使用​​することはできない場合がありますViewPropertyAnimator

于 2014-06-07T08:54:15.713 に答える
0

Visibility.GONEをまったく使用しなくても、SO全体の答えはどれもうまくいきませんでした。

だから私はバンドエイドで終わったので、いつかそれを調べます.

私の一時的な解決策は、高さを 1px に設定し (0dp ではなく、私の場合は機能しません)、可視性を INVISIBLE に設定することです。だから私は1pxを失うことになりますが、気づくのはかなり難しいです.

コード:

ResizeAnimation.kt

class ResizeAnimation(private val view: View, private val newHeight: Int) : Animation() {
    private val initialHeight: Int = view.layoutParams.height
    private val deltaHeight: Int

    init {
        deltaHeight = newHeight - initialHeight
    }

    override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
        view.layoutParams.height = (initialHeight + deltaHeight * interpolatedTime).toInt()
        view.requestLayout()
    }

    override fun willChangeBounds(): Boolean {
        return true
    }
}

使用法:

private fun displayProgressBar() {
        progressBar.visibility = View.VISIBLE
        val animation = ResizeAnimation(progressBar, 78).apply {
            duration = inAnimationDuration
        }
        progressBar.startAnimation(animation)
    }

private fun removeProgressBar() {
        val animation = ResizeAnimation(progressBar, 1).apply {
            duration = outAnimationDuration
        }
        progressBar.startAnimation(animation)
        progressBar.visibility = View.INVISIBLE
    }

それを最終的な解決策と見なさず、応急処置として扱ってください。

于 2020-08-24T09:46:24.590 に答える