6

I have several Views within a FrameLayout. There is a transition I have written where each view has a custom Animation class applied. During this transition, I need to bring the View at the bottom of the z-order to the front. I do this with:

    public static void putBackAtFront(ViewGroup v) 
    {
        v.getChildAt(0).bringToFront();
        refreshEverything(v);
    }

This gets called from within the applyTransformation() of my custom Animation.

i.e.

public class PivotAnimation extends Animation {
    private View view;
    ...
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) 
    {
        ...
        if(interpolatedTime >= 1.f && isAtBack(view))
        {
           putBackAtFront(view);
        }
        ...
    }
    ...
}

refreshEverything() calls invalidate() and requestLayout() on the parent FrameLayout and all its children.

Everything works perfectly except that when putBackAtFront() is called, the View that is now at the bottom disappears for a single frame before instantly re-appearing, resulting in a noticeable flicker. I've also tried without calling refreshEverything(), it makes no difference.

I'm targeting API Level 7.

sleep
  • 4,855
  • 5
  • 34
  • 51

2 Answers2

1

applyTransformation() is called multiple times during the animation so you should do the animation based on the interpolatedTime, when its 1.0, the animation is at the end, so you should call your bring to front here.

So in my opinion this flicker happens when in some of these calls to your method, the getChildAt(0) gets a different view than the one you want and the flicker appears.

Marcio Covre
  • 4,556
  • 2
  • 22
  • 24
  • Sorry, I've updated my question to clarify. I am already doing as you say; putBackAtFront() is only called once at the end of the transition, not every time. – sleep Apr 03 '12 at 03:08
0

I'm thinking it has to be one of three things:

If you're building with the 3.0+ APIs, you may have hardware acceleration enabled. This is also on by default in 4.0. You can try using

    setLayerType(LAYER_TYPE_SOFTWARE, null);

to disable HW acceleration on that layout/view/window.

Also, you may not need to call requestLayout(), if all the views are children of a relativelayout, a z-index change shouldnt concern it.

Calling invalidate almost might not be needed. Have you tried making the Views focusable and just calling requestFocus() instead of bringToFront() at all? bringToFront() apparently removes the view from its parent and re-appends it. This could easily cause an invalidation between the steps, as I dont think anything is pausing the drawing while this is happening.

Colin Godsey
  • 1,293
  • 9
  • 14
  • Thanks for the suggestions. As stated in the question, I'm targeting API 7 (2.1), so HW acceleration is not an option for me. requestFocus() won't change the z order, which I need to happen. Also as stated in the question I've tried with and without requestLayout() and invalidate(). In any case, bringToFront() is called on the UI (main) thread so, this - according to the docs - should by definition "pause" the drawing. Unless the docs aren't telling the full story, and there is some async rendering going on. – sleep Apr 10 '12 at 03:16