alexjlockwood / adp-activity-transitions

This sample app accompanies a series of blog posts I wrote on transitions in Android
https://www.androiddesignpatterns.com/2014/12/activity-fragment-transitions-in-android-lollipop-part1.html
542 stars 94 forks source link

Edge case issue on shared element transition return #3

Open lawloretienne opened 8 years ago

lawloretienne commented 8 years ago

Great repo. Thanks a lot for this. However I found an issue. This is pretty edge case stuff so i'm not sure its a high priority. If you go to the DetailActivity and start quickly swiping through DetailFragments and you click the back button in the middle of this, it will mess up the return transition of the Shared Element. The back button has to be clicked in the middle of switching between fragments in the FragmentStatePagerAdapter. Any ideas how to fix this?

gaoneng102 commented 8 years ago

@lawloretienne Did you fix this?and how?

lawloretienne commented 8 years ago

I did not fix this @gaoneng102 , I am hoping that @alexjlockwood can provide some insight.

gaoneng102 commented 8 years ago

@lawloretienne https://github.com/alexjlockwood/activity-transitions/issues/5

lawloretienne commented 8 years ago

@gaoneng102 which answer is it in that stack overflow post : (http://stackoverflow.com/questions/8785221/retrieve-a-fragment-from-a-viewpager) ?

gaoneng102 commented 8 years ago

`public class MyPagerAdapter extends FragmentStatePagerAdapter { SparseArray registeredFragments = new SparseArray();

public MyPagerAdapter(FragmentManager fm) {
    super(fm);
}

@Override
public int getCount() {
    return ...;
}

@Override
public Fragment getItem(int position) {
    return MyFragment.newInstance(...); 
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    Fragment fragment = (Fragment) super.instantiateItem(container, position);
    registeredFragments.put(position, fragment);
    return fragment;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    registeredFragments.remove(position);
    super.destroyItem(container, position, object);
}

public Fragment getRegisteredFragment(int position) {
    return registeredFragments.get(position);
}

}`

lawloretienne commented 8 years ago

@gaoneng102 can you explain how this fixes the shared element return transition?

gaoneng102 commented 8 years ago

@Override public void setPrimaryItem(ViewGroup container, int position, Object object) { super.setPrimaryItem(container, position, object); mCurrentDetailsFragment = (DetailsFragment) object; } mCurrentDetailsFragment maybe the last fragment,when scrolling the viewpager fastly,so use getRegisteredFragment(int position) and mCurrentDetailsFragment must be the next one ,then the return transition work well.

lawloretienne commented 8 years ago

I just tried this

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
//  super.setPrimaryItem(container, position, object);
//  currentDetailsFragment = (GalleryDetailsFragment) object;
    currentDetailsFragment = (GalleryDetailsFragment) getRegisteredFragment(position);
    super.setPrimaryItem(container, position, currentDetailsFragment);
}

but it did not fix the return transition.

gaoneng102 commented 8 years ago

remove setPrimaryItem(),use instantiateItem() and destroyItem() above.and use getRegisteredFragment() like that:

SharedElementCallback mCallback = new SharedElementCallback() { @Override public void onMapSharedElements(List names, Map<String, View> sharedElements) { if (mIsReturning) { View sharedElement = null; if (adapter!=null) { pictureShowFragment = adapter.getRegisteredFragment(mCurrentPosition); } if (pictureShowFragment != null) { sharedElement = pictureShowFragment.getTransitionView(); } if (sharedElement == null) { // If shared element is null, then it has been scrolled off screen and // no longer visible. In this case we cancel the shared element transition by // removing the shared element from the shared elements map. names.clear(); sharedElements.clear(); } else if (mStartingPosition != mCurrentPosition) { // If the user has swiped to a different ViewPager page, then we need to // remove the old shared element and replace it with the new shared element // that should be transitioned instead. String transitionName=ViewCompat.getTransitionName(sharedElement); names.clear(); names.add(transitionName); sharedElements.clear(); sharedElements.put(transitionName, sharedElement); } } } };

lawloretienne commented 8 years ago

Thanks. This seems to work a little bit better. But if I stress test it, it ends up doing a massive garbage collection. So I don't know what is leaking memory but it causes my app to hang.