互いに積み重なった 3 つのビューをアニメーション化しています。前面ビューではないビューをタップすると、1 つまたは 2 つのビューが上下にスライドしてタップされたビューを明らかにし、タップしたビューを前面に移動してから、すべてを元の位置に戻します。これらのほとんどは正常に動作します。アニメーション化したばかりのビューを前面に持ってきたときにのみ、ちらつきが目立ちます。
少なくとも 100 件の投稿を読みましたが、解決策が含まれている投稿はありません。提案されたすべての解決策を 1 か所にまとめ、できれば解決策を見つけるために、これを投稿しています。
アニメーションはビュー自体をアニメーション化するのではなく、単なる画像であることを知っています。ビューは元の位置にとどまります。それと関係があるのは間違いない。移動したばかりのビューを前面に持ってくる場合にのみ発生します。
アニメーションを開始する前またはアニメーションが終了した後にビューをアニメーションの終了位置に移動しても、少しは役に立ちません。
またAnimationListener.onAnimationEnd
、私は独自の見解を導き出し、そこでインターセプトしたため、バグとは関係ありませんonAnimationEnd
。
と を使用Animation.setFillAfter
しAnimation.setFillEnabled
て、アニメーションの終了位置に最終画像を保持しています。
使用してみAnimation.setZAdjustment
ましたが、それは画面内のビューではなく、画面全体でのみ機能します。
私が学んだことから、問題はbringToFront()
それ自体にあると思われます。これはremoveChild()/addChild()
、親ビューを実行します。おそらく、removeChild
削除された子なしでビューを簡単に表示する再描画が原因です。
だから私の質問:これを修正できる何か私が見逃したものを見た人はいますか?Androidには、描画を一時的に停止し、後で描画を再開するコマンドがある可能性があります。setUpdateScreen(false) / setUpdateScreen(true)
ペアみたいなもの?これにより、ちらつきの段階をスキップできます。
効果をデモするための最小限のコードは次のとおりです。白をタップすると、ちらつきのない白の後ろで赤が上下に移動します(白は前に出ますが動きません)。次に赤をタップすると、赤が白の後ろから上に移動し、赤が白の上にスライドする直前に前面に移動するとちらつきます。奇妙なことに、赤の代わりに青を使用すると、同じことが常に発生するとは限りません。
MainActivity.java
package com.example.testapp;
import com.example.testapp.ImagePanel.AnimationEndListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.TranslateAnimation;
public class MainActivity extends Activity
{
private static final int ANIMATION_TIME = 1000;
private ImagePanel mRed;
private ImagePanel mWhite;
private ImagePanel mBlue;
private int mFrontPanelId;
private void animate(final ImagePanel panel, final int yFrom, final int yTo,
final AnimationEndListener animationListener)
{
final TranslateAnimation anim = new TranslateAnimation(0, 0, 0, 0, 0, yFrom, 0, yTo);
anim.setDuration(ANIMATION_TIME);
anim.setFillAfter(true);
anim.setFillEnabled(true);
if (animationListener != null)
{
panel.setAnimListener(animationListener);
}
panel.startAnimation(anim);
}
public void onClick(final View v)
{
final int panelId = v.getId();
if (mFrontPanelId == panelId)
{
return;
}
final ImagePanel panel = (ImagePanel) v;
final int yTop = mWhite.getTop() - mRed.getBottom();
final int yBot = mWhite.getBottom() - mBlue.getTop();
final boolean moveRed = panelId == R.id.red || mFrontPanelId == R.id.red;
final boolean moveBlue = panelId == R.id.blue || mFrontPanelId == R.id.blue;
animate(mBlue, 0, moveBlue ? yBot : 0, null);
animate(mRed, 0, moveRed ? yTop : 0, new AnimationEndListener()
{
public void onBegin()
{
}
public void onEnd()
{
// make sure middle panel always stays visible
if (moveRed && moveBlue)
{
mWhite.bringToFront();
}
panel.bringToFront();
animate(mBlue, moveBlue ? yBot : 0, 0, null);
animate(mRed, moveRed ? yTop : 0, 0, new AnimationEndListener()
{
public void onBegin()
{
}
public void onEnd()
{
}
});
mFrontPanelId = panelId;
}
});
}
@Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRed = (ImagePanel) findViewById(R.id.red);
mWhite = (ImagePanel) findViewById(R.id.white);
mBlue = (ImagePanel) findViewById(R.id.blue);
mFrontPanelId = R.id.red;
}
}
ImagePanel.java
package com.example.testapp;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
public class ImagePanel extends ImageView
{
public interface AnimationEndListener
{
public void onBegin();
public void onEnd();
}
private AnimationEndListener mAnim = null;
public ImagePanel(final Context context)
{
super(context);
}
public ImagePanel(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public ImagePanel(final Context context, final AttributeSet attrs, final int defStyle)
{
super(context, attrs, defStyle);
}
@Override
protected void onAnimationEnd()
{
super.onAnimationEnd();
clearAnimation();
if (mAnim != null)
{
final AnimationEndListener anim = mAnim;
mAnim = null;
anim.onEnd();
}
}
@Override
protected void onAnimationStart()
{
super.onAnimationStart();
if (mAnim != null)
{
mAnim.onBegin();
}
}
public void setAnimListener(final AnimationEndListener anim)
{
mAnim = anim;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.example.testapp.ImagePanel
android:id="@+id/blue"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="#000080"
android:src="@drawable/testpattern"
android:onClick="onClick" />
<com.example.testapp.ImagePanel
android:id="@+id/white"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:background="#808080"
android:src="@drawable/testpattern"
android:onClick="onClick" />
<com.example.testapp.ImagePanel
android:id="@+id/red"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:adjustViewBounds="true"
android:background="#800000"
android:src="@drawable/testpattern"
android:onClick="onClick" />
</RelativeLayout>
testpattern.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<gradient
android:startColor="#00000000"
android:endColor="#ffffffff" />
</shape>