Android - TransitionDrawable starting in 'end' state flickers when initially drawn

641 Views Asked by At

I have a RecyclerView holding a list of Artists. An artist can be marked as a favorite or not a favorite.

There's a heart to represent this state, and I have a transition drawable, where I'm going from a outlined heart, to a filled in heart based on if the artist in question has been marked as a favorite. The animation itself is working correctly and smoothly transitions between the two when the user clicks on the heart, and looks beautiful.

        TransitionDrawable td = new TransitionDrawable(new Drawable[]{
                ContextCompat.getDrawable(getActivity(), R.drawable.favorite_border),
                ContextCompat.getDrawable(getActivity(), R.drawable.favorite)});

        artistViewHolder.image.setImageDrawable(td);

        if (artist.isFavorite()) {
            td.startTransition(0);
        }

In the onClick for the item, I call either .reverseTransition(300) or .startTransition(300) depending on the next state.

I'm running into problems anytime the view is created (1st screen load) and I need to start in the 2nd position (favorite). The initial load you can see it flicker from the empty heart to the filled heart, even though my animation time is set to 0 when it's created. This also happens anytime the list gets invalidated such as if it gets filtered into a smaller set of artists.

I guess since it needs to do things and isn't actually just setting the drawable, 0 isn't actually "instant". I can't find any other way to start in the "end" position though, other than to reverse the starting position of the images in the transition drawable itself.

If I do that though, start/reverse are going to behave differently on a heart by heart basis. At best, I would need to extend the transition drawable, and override the start/reverse/reset methods to take into account which initial state it's in, and that seems kind of hacky?

Am I missing something obvious to start in the end position but not cause that flicker?

Thanks!

2

There are 2 best solutions below

0
Ben987654 On

Unless there's a better way to do this, I've gone ahead and extended it, and flipped the start/reverse call based off the initial state.

public class MyTransitionDrawable extends TransitionDrawable{

private boolean initialFavorite = false;

public MyTransitionDrawable(Drawable[] layers) {
    super(layers);
}

public MyTransitionDrawable(Drawable[] layers, boolean initialFavorite) {
    super(layers);
    this.initialFavorite = initialFavorite;
}

public boolean isInitialFavorite() {
    return initialFavorite;
}

@Override
public void startTransition(int durationMillis) {
   if(!initialFavorite){
       super.startTransition(durationMillis);
   }else{
       super.reverseTransition(durationMillis);
   }
}

@Override
public void reverseTransition(int durationMillis) {
    if(!initialFavorite){
        super.reverseTransition(durationMillis);
    }else{
        super.startTransition(durationMillis);
    }
}
}

`

1
princeparadoxes On

You don't migtht remove flicker on td.startTransition(0); So, you need change order in your Drawables array. For example

Drawable favorite_border = ContextCompat.getDrawable(getActivity(), R.drawable.favorite_border);
Drawable favorite = ContextCompat.getDrawable(getActivity(), R.drawable.favorite);
TransitionDrawable td = new TransitionDrawable(isFavorite
                ? new Drawable[]{favorite, favorite_border}
                : new Drawable[]{favorite_border, favorite});

artistViewHolder.image.setImageDrawable(td);

This will work provided that you do this in onBindViewHolder