Android bringToFront导致闪烁

时间:2012-07-24 22:20:45

标签: android animation flicker

我正在制作三个叠加在一起的视图。当我点击一个不是正视图的视图时,一个或两个视图将向上或向下滑动以显示点击的视图,将点击的视图置于前面,然后将所有内容返回到其原始位置。其中大多数工作正常。只有当我把一个视图带到前面时,我才会看到一个明显的闪烁。

我已经阅读了至少一百个帖子,但没有一个包含解决方案。 我发布此信息是为了在一个地方整合所有建议的解决方案,并希望找到解决方案。

我知道动画不会为视图本身设置动画,而只是图像。视图保持原始位置。这肯定与此有关。它只会在将视图移到刚刚移动的前方时发生。

在开始动画之前或动画结束之后将视图移动到动画结束位置并没有帮助。

它也与AnimationListener.onAnimationEnd错误无关,因为我在那里派生了自己的观点并拦截了onAnimationEnd

我正在使用Animation.setFillAfterAnimation.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>

3 个答案:

答案 0 :(得分:0)

您是否需要随时查看所有图像?你可以将他们的能见度设置为不可见,这样他们就不会打扰你。一旦你需要它们,你就可以再次看到它们。

答案 1 :(得分:0)

尝试在animation.cancel()中致电onAnimationEnd。我记得有一段时间我在执行onAnimationEnd中的代码后出现类似的动画闪烁问题,这就解决了这个问题。

答案 2 :(得分:0)

在动画期间调用bringToFront()时,我正在观察同样的问题。

我可以在包含我动画的孩子的setChildrenDrawingOrderEnabled(boolean enabled)上使用getChildDrawingOrder(int childCount, int i)ViewGroup来解决我的问题。