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?

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
Michell Bak
  • 13,182
  • 11
  • 64
  • 121
  • What transitions are you using? – klmprt Nov 03 '14 at 16:16
  • Sorry, forgot to mention that. It's the default `@android:transition/move` transition. – Michell Bak Nov 03 '14 at 16:26
  • 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. – Alex Lockwood Nov 03 '14 at 18:57
  • @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. – Michell Bak Nov 03 '14 at 19:02

1 Answers1

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).

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • 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. – Michell Bak Nov 03 '14 at 19:55
  • 1
    You may need to call postponeEnterTransition from the onCreate() of the Activity. – George Mount Nov 03 '14 at 23:53
  • 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! – Michell Bak Nov 04 '14 at 23:11
  • 2
    @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. – Alex Lockwood Nov 05 '14 at 00:11
  • @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. – George Mount Nov 05 '14 at 15:12
  • I had the same issue. Here is a good example app of reloading a highres AFTER the transition: https://play.google.com/store/apps/details?id=com.musenkishi.wally (actually referenced from this tutorial: http://www.androiduipatterns.com/2014/09/material-design-activity-transition.html ) – tir38 Dec 03 '14 at 21:21
  • @tir38 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: http://stackoverflow.com/questions/35846447/android-sharedelementtransition-imageview-not-moving-properly – Jemshit Mar 07 '16 at 14:49
  • @JemshitIskenderov That is not my application so I don't have any source. – tir38 Mar 11 '16 at 22:17