Search code examples
androidandroid-transitions

Android TransitionDrawable not fading


I have an ImageView and I am trying to fade from one image to the next using this code:

Drawable bgs[] = new Drawable[2];
public void redraw(int[][] grid) {
    bgs[0] = bgs[1];
    bgs[1] = new GameDrawable(grid, prefs.colors);
    if (bgs[0] == null) {
        gameField.setImageDrawable(bgs[1]);
    } else {
        TransitionDrawable crossfader = new TransitionDrawable(bgs);
        crossfader.setCrossFadeEnabled(true);
        gameField.setImageDrawable(crossfader);
        crossfader.startTransition(500);
    }
}

gameField is correctly referenced as an ImageView.

gameDrawable simply extends Drawable and draws the grid.

On each move and action the new GameDrawable is being rendered correctly but there is no fading whatsoever. The new image is simply displayed instantaneously. I have tried lengthening the transition time and swapping the order of the drawables with no effect.

Any help on is appreciated.

Update: I have now set my transition to something ridiculously long like 500000. The first drawable shows for a few seconds and then suddenly the second drawable appears. So still no transition.

Update 2: I think my Drawable might be implemented incorrectly, so I have attached the code.

public class GameDrawable extends Drawable {

    private Paint paint = new Paint();
    private float blockWidth = 1;
    private int[][] myGrid;
    private int myColor;
    private List<Point> myPoints;

    public GameDrawable(int[][] grid) {
        super();
        this.myGrid = grid;
        this.myColor = colors[yourColor];
        paint.setStrokeWidth(1);
        paint.setStyle(Paint.Style.FILL);
        paint.setAlpha(0);
        this.myPoints = yourPoints;
    }

    @Override
    public void draw(Canvas canvas) {
        float height = getBounds().height();
        float width = getBounds().width();
        blockWidth = width / myGrid.length;
        if (height / myGrid.length < blockWidth) {
            blockWidth = height / myGrid.length;
        }

        for (int x = 0; x < myGrid.length; x++) {
            for (int y = 0; y < myGrid[x].length; y++) {
                paint.setColor(colors[myGrid[x][y]]);
                canvas.drawRect(x * blockWidth, y * blockWidth, (x+1)*blockWidth, (y+1)*blockWidth, paint);
            }
        }
    }

    @Override
    public void setAlpha(int alpha) {
        paint.setAlpha(alpha);
        invalidateSelf();
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        paint.setColorFilter(cf);
        invalidateSelf();
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}

Solution

  • Looking at your code, I see a problem at the line

    bgs[0] = bgs[1];
    

    bgs[1] has not yet been defined before this line and so bgs[0] is null for the first method call. Because of this, (bgs[0] == null) is true, and so the later defined bgs[1] is directly set to the gameField ImageView.

    Use corrected code below.

    Drawable bgs[] = new Drawable[2];
    Drawable firstDrawable = getResources().getDrawable(R.drawable.transparent);
    
    public void redraw(int[][] grid) {
        bgs[0] = firstDrawable;
        bgs[1] = new GameDrawable(grid, prefs.colors);
        firstDrawable = bgs[1];
        TransitionDrawable crossfader = new TransitionDrawable(bgs);
        crossfader.setCrossFadeEnabled(true);
        gameField.setImageDrawable(crossfader);
        crossfader.startTransition(500);
    }
    

    Note that TransitionDrawable does not work properly when the Drawable sizes are different. So you may need to resize firstDrawable beforehand.

    EXTRA: I would avoid setCrossFadeEnabled(true) since the whole TransitionDrawable becomes translucent during the transition, revealing the background. Sometimes, this creates a "blinking" effect and destroys the smoothness of the transition.

    EDIT: Looking at your custom Drawable implementation, I think the problem lies in the line

    canvas.drawColor(Color.WHITE);
    

    in the draw() method.

    I looked at TransitionDrawable.java source and found that setAlpha is called on the drawables to get the cross fade effect. However, your canvas has a solid white color and setAlpha() only affects the paint. Hope this is your answer.

    EDIT 2: The actual problem, as pointed out by Michael, was that TransitionDrawable's setAlpha() calls on the Drawables were rendered ineffective due to paint.setColor() in the GameDrawable's draw() method overriding the paint's alpha value set by the TransitionDrawable.