2012-07-24 138 views
2

我正在爲彼此堆疊的三個視圖設置動畫。當我點擊一個不是前視圖的視圖時,一個或兩個視圖會向上或向下滑動以揭示拍攝視圖,將拍攝視圖置於前方,然後將所有視圖恢復到原始位置。這些大多數工作正常。只有當我看到前面的動畫時,我纔會看到一個明顯的閃爍。Android bringToFront導致閃爍

我已閱讀至少一百個帖子,但沒有包含解決方案。 我張貼此來鞏固每個建議的解決方案在一個地方,並希望找到一個解決方案。

我知道動畫不會爲視圖本身設置動畫,而只是一個圖像。視圖保持原來的位置。這肯定與此有關。只有在將視圖移到剛移動的前方時纔會發生。

在開始動畫之前或動畫完成之後將視圖移動到動畫結束位置並沒有幫助。

它也與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> 

回答

0

你所需要的所有圖片可在任何時間可見?你可以將他們的能見度設置爲不可見,所以他們不會打擾你。一旦你需要它們,你就可以再次看到它們。

+0

在演示應用程序中只有3張圖像,並且每個圖像的一部分始終可見。 其實我正在建設的應用程序有這個問題有更多的圖像,我確實使不可見的應用程序不可見。 – 2012-07-25 16:27:28

0

嘗試在onAnimationEnd中調用animation.cancel()。我記得有一回,我在執行onAnimationEnd中的代碼之後出現了動畫閃爍的類似問題,並且做了這個訣竅。

+0

謝謝。我也嘗試過。忘了提一個。 這肯定是導致閃爍的'bringToFront()'。 – 2012-07-31 05:58:39

0

我在動畫過程中調用bringToFront()時觀察到同樣的問題。

我可以通過在ViewGroup上使用setChildrenDrawingOrderEnabled(boolean enabled)getChildDrawingOrder(int childCount, int i)來解決我的問題,該包含我正在動畫的孩子。

+0

我試過了。我擴展了根佈局並實現了getChildDrawingOrder。但爲了讓屏幕反映新的順序,您仍然需要從bringChildToFront調用invalidate(),這仍然會導致正在進行的動畫閃爍。 還是你有不同的做法? – slott 2015-05-07 12:11:26