J'anime trois vues empilées les unes sur les autres. Lorsque je tape sur une vue qui n'est pas la vue de face, une ou deux vues vont glisser vers le haut ou vers le bas pour découvrir la vue tapée, amener la vue tapée à l'avant, puis tout ramener à leur position d'origine. La plupart d'entre eux fonctionnent bien. Ce n'est que lorsque j'apporte une vue à l'avant que je m'anime juste que j'obtiens un scintillement perceptible.Android bringToFront provoque le scintillement
J'ai lu au moins une centaine de messages mais aucun ne contient la solution. Je poste ceci pour consolider chaque solution suggérée dans un endroit et trouver avec optimisme une solution.
Je sais que l'animation n'anime pas la vue elle-même, mais juste une image. La vue reste à sa position d'origine. C'est certainement lié à cela. Cela n'arrive que lorsqu'on amène une vue à l'avant qui vient de bouger.
Le déplacement de la vue vers la position finale de l'animation avant le démarrage de l'animation ou après la fin de l'animation n'aide pas un bit.
Il n'est pas non plus lié au bogue AnimationListener.onAnimationEnd
, puisque j'ai dérivé mes propres vues et intercepte onAnimationEnd
là. J'utilise Animation.setFillAfter
et Animation.setFillEnabled
pour conserver l'image finale à l'emplacement final de l'animation.
J'ai essayé d'utiliser Animation.setZAdjustment
mais celui-ci ne fonctionne que pour des écrans entiers, pas des vues dans un écran. De ce que j'ai appris je suspecte que le problème est bringToFront()
lui-même, qui fait un removeChild()/addChild()
sur la vue de parent. Peut-être que le removeChild
provoque le redessin montrant la vue sans l'enfant retiré brièvement.
Donc, mes questions: Quelqu'un voit-il quelque chose que j'ai raté qui pourrait résoudre ce problème? Est-ce que Android peut avoir une commande pour arrêter temporairement le dessin et reprendre le dessin plus tard. Quelque chose comme une paire setUpdateScreen(false)/setUpdateScreen(true)
? Cela me permettrait d'ignorer l'étape scintillement.
Le code minimal pour démo l'effet suit. Appuyez sur le blanc pour voir le rouge remonter et redescendre derrière le blanc sans scintillement (le blanc arrive à l'avant mais ne bouge pas). Ensuite, appuyez sur le rouge pour voir le rouge remonter derrière le blanc et le scintillement quand il est amené à l'avant juste avant qu'il ne glisse vers le bas sur le blanc. Chose étrange est que la même chose ne se produit pas toujours lorsque vous utilisez bleu au lieu de rouge.
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>
Il y a seulement 3 images dans l'application de démonstration et des parties de chacune sont visibles en tout temps. En fait, l'application que je construis qui a ce problème a encore plus d'images et je fais les invisibles. –