Weird issue when transitioning ImageView in Android 5.0
Asked Answered
A

1

9

I'm experiencing a strange issue / bug regarding ImageView transitions between Activities in Android 5.0.

I'm trying to transition a thumbnail image from Fragment A (in Activity A) to the header image of Fragment B (in Activity B). It works well most of the time, but it sometimes messes up ever so slightly.

Here's a picture of what it looks like when it messes up:

What a mess... :-)

Naturally, it's supposed to fill the entire area. Both ImageViews are set to ScaleType.CENTER_CROP, so I can't imagine that being the issue.

What's curious is that the issue fixes itself immediately upon scrolling in Activity B (everything is contained within a subclassed ScrollView that changes the ImageView padding upon scrolling).

The code for launching Activity B is pretty simple:

ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
    activity, thumbImageView, "cover"); // "cover" is the shared element name for both ImageViews
ActivityCompat.startActivity(activity, intent, options.toBundle());

Here's the code for the observable ScrollView listener:

scrollview.setOnScrollChangedListener(new OnScrollChangedListener() {
    @Override
    public void onScrollChanged(ScrollView who, int l, int t, int oldl, int oldt) {
        // Such parallax, much wow
        headerImageView.setPadding(0, (int) (t / 1.5), 0, 0);
    }
});

Also, here's part of my theme style:

<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>

Any ideas?

Antonyantonym answered 3/11, 2014 at 15:35 Comment(4)
What transitions are you using?Chromatin
Sorry, forgot to mention that. It's the default @android:transition/move transition.Antonyantonym
How frequently does the bug happen (i.e. every time, randomly, etc.). Also, does the bug still happen if you comment out the setPadding() code in your scroll view listener? I'm just trying to understand the root cause of why this might be happening.Remittent
@AlexLockwood It appears to be quite random, but I'd say it happens ~25% of the time. Yes, it does happen when I comment out setPadding(), but if I do that, it won't automatically fix itself when I scroll. It'll just stay bugged.Antonyantonym
R
4

Try adding the following code to your Fragment B's onCreateView() method:

getActivity().postponeEnterTransition(); 
scrollView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 
    public boolean onPreDraw() { 
        scrollView.getViewTreeObserver().removeOnPreDrawListener(this);
        getActivity().startPostponedEnterTransition();
        return true;
    }
});

Does the problem still occur when this code is present? This will ensure that the transition only begins after the fragment has finished its layout.

You might even need to call startPostponedEnterTransition() later than this... for example, if you are loading a high resolution image in your second activity, try calling startPostponedEnterTransition after the image has been loaded (i.e. set the onPreDraw listener on the ImageView instead of on the window's decor view).

Remittent answered 3/11, 2014 at 19:11 Comment(8)
Sadly, it still occurs. It looks like the thumbnail ImageView gets transitioned without changing its bounds to the wider bounds of the ImageView in Activity B.Antonyantonym
You may need to call postponeEnterTransition from the onCreate() of the Activity.Pyrogallol
I managed to figure out the exact reason for this. It seems to be caused by loading a different (higher resolution) image in Activity B. I've used your proposal, except I'm using getActivity().startPostponedEnterTransition() after the higher resolution image has been loaded. Not optimal, as it's quite a bit slower, but it works!Antonyantonym
@GeorgeMount can correct me if I'm wrong, but I believe one way of dealing with slow-loading high resolution images is to take advantage of the "snapshots" the framework takes of your shared elements before the transition begins. If you call Activity#setEnterSharedElementCallback() and then override onSharedElementStart(), the third argument provides you with a list of "snapshot views" that can be used as a placeholder during the transition if the high resolution image is not yet loaded. I've never tested this myself, but just wanted to let you know it exists.Remittent
@AlexLockwood is correct. You could wait until after the shared element is transitioned before replacing the lower resolution image with the higher resolution one. Since the view is in motion, it won't look too bad.Pyrogallol
I had the same issue. Here is a good example app of reloading a highres AFTER the transition: play.google.com/store/apps/details?id=com.musenkishi.wally (actually referenced from this tutorial: androiduipatterns.com/2014/09/… )Sitwell
@Sitwell Can you please share a sample code or how did you achieve that, is that snapshot view you place before downloading view, or cache of image ? and what transitions you are using. I have problem stated here: #35846947Synergistic
@JemshitIskenderov That is not my application so I don't have any source.Sitwell

© 2022 - 2024 — McMap. All rights reserved.