TalMihr
TalMihr

Reputation: 1548

Android shared element transition whole screen flickers on reenter

I am trying to create a "simple" image shared element transition between a recycler view item (Activity A) & a view pager (Activity B). I have managed to smoothen everything but it seems that no matter how I set my exit/reenter/enter/return transitions the transition back from B to A, when the shared element is settled back, is flickering. And by flickering I mean the entire screen.

I am using AppCompat themes & ActivityCompat methods with combinations of PreDrawListeners in both A (reenter) and B (when image is set using Glide).

Heres Activity A related code:

private Bundle mReenterState;

@TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override protected void initActivityTransitions() {
    super.initActivityTransitions();
    getWindow().setSharedElementsUseOverlay(false);
    setExitSharedElementCallback(mCallback);
}

private final SharedElementCallback mCallback = new SharedElementCallback() {
    @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        if (mReenterState != null) {
            int startingSelection = mReenterState.getInt(DefinesGlobal.KEY_STARTING_INDEX);
            int currentSelection = mReenterState.getInt(DefinesGlobal.KEY_CURRENT_INDEX);
            if (startingSelection != currentSelection) {
                String newTransitionName = mHotel.getDetail().getHotelImagesGallery().get(currentSelection);
                View newSharedElement = mContentView.getGalleryView().getRecyclerViewPager()
                        .getLayoutManager().findViewByPosition(currentSelection);
                if (newSharedElement != null) {
                    names.clear();
                    names.add(newTransitionName);
                    sharedElements.clear();
                    sharedElements.put(newTransitionName, newSharedElement);
                }
            }
            mReenterState = null;
        } else {
            // If mReenterState is null, then the activity is exiting.
            View navigationBar = findViewById(android.R.id.navigationBarBackground);
            View statusBar = findViewById(android.R.id.statusBarBackground);
            if (navigationBar != null) {
                names.add(navigationBar.getTransitionName());
                sharedElements.put(navigationBar.getTransitionName(), navigationBar);
            }
            if (statusBar != null) {
                names.add(statusBar.getTransitionName());
                sharedElements.put(statusBar.getTransitionName(), statusBar);
            }
        }
    }
};

@Override public void onActivityReenter(int resultCode, Intent data) {
    super.onActivityReenter(resultCode, data);
    mReenterState = new Bundle(data.getExtras());
    int startingSelection = mReenterState.getInt(DefinesGlobal.KEY_STARTING_INDEX);
    int currentSelection = mReenterState.getInt(DefinesGlobal.KEY_CURRENT_INDEX);
    if (startingSelection != currentSelection) {
        mContentView.getGalleryView().getRecyclerViewPager().scrollToPosition(currentSelection);

    }
    ActivityCompat.postponeEnterTransition(this);
    mContentView.getGalleryView().getRecyclerViewPager().getViewTreeObserver()
            .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            mContentView.getGalleryView().getRecyclerViewPager().getViewTreeObserver().removeOnPreDrawListener(this);
            mContentView.getGalleryView().getRecyclerViewPager().requestLayout();
            ActivityCompat.startPostponedEnterTransition(ViewModelHotelDetailsActivity.this);

            return true;
        }
    });
}

Heres Activity B related code.

private boolean mIsReturning;

@Override public void finishAfterTransition() {
    mIsReturning = true;
    Intent data = new Intent();
    data.putExtra(DefinesGlobal.KEY_CURRENT_INDEX, mCurrentSelection);
    data.putExtra(DefinesGlobal.KEY_STARTING_INDEX, mStartingSelection);
    setResult(RESULT_OK, data);
    super.finishAfterTransition();
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override protected void initActivityTransitions() {
    super.initActivityTransitions();
    ActivityCompat.postponeEnterTransition(this);
    setEnterSharedElementCallback(mCallback);
}

private final SharedElementCallback mCallback = new SharedElementCallback() {
    @TargetApi(Build.VERSION_CODES.LOLLIPOP) @Override public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        if (mIsReturning) {
            ViewModelFullSizeGalleryFragment fragment =
                    ((FullSizeGalleryPagerAdapter) mPager.getAdapter()).getCurrent();
            ImageView sharedElement = fragment.getImageView();
            if (sharedElement == null) {
                names.clear();
                sharedElements.clear();
            } else if (mStartingSelection != mCurrentSelection) {
                names.clear();
                names.add(sharedElement.getTransitionName());
                sharedElements.clear();
                sharedElements.put(sharedElement.getTransitionName(), sharedElement);
            }
        }
    }
};

Activity B view pager fragment:

ublic class ViewModelFullSizeGalleryFragment extends ViewModelBaseFragment {

@Override protected int getLayoutId() {
    return R.layout.view_model_fragment_full_size_gallery;
}

@Bind(R.id.full_size_image_view) ImageView mImageView;

public static ViewModelFullSizeGalleryFragment newInstance(String url, int position, int
        target) {
    ViewModelFullSizeGalleryFragment fragment = new ViewModelFullSizeGalleryFragment();
    fragment.setUrl(url);
    fragment.setIndexAndTarget(position, target);
    return fragment;
}

private String mUrl;
private int mPosition;
private int mTarget;

public void setUrl(String url) {
    mUrl = url;
}

public void setIndexAndTarget(int position, int target) {
    mPosition = position;
    mTarget = target;
}

@Override protected void initViewModel(View view) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        mImageView.setTransitionName(mUrl);
    }
    Glide.with(getContext())
            .load(mUrl)
            .transform(new HotelDetailsImageTransformation(getContext(),
                    LMTApplication.mWidth))
            .diskCacheStrategy(DiskCacheStrategy.ALL)
            .skipMemoryCache(true)
            .error(R.drawable.ic_nopic)
            .into(new SimpleTarget<GlideDrawable>() {
                @Override public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
                    if (mImageView != null && resource != null) {
                        mImageView.setImageDrawable(resource);
                        mImageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                            @Override public boolean onPreDraw() {
                                mImageView.getViewTreeObserver().removeOnPreDrawListener(this);
                                if (mTarget == mPosition)
                                    ((ISharedElementCallback) getContext()).onViewReadyForTransition();
                                return true;
                            }
                        });

                    }
                }
            });
}

@Override public void onBackPressed() {
    //!! Not used.
}

public interface ISharedElementCallback {
    void onViewReadyForTransition();
}

public ImageView getImageView() {
    return mImageView;
}

Havent figured out what actually does the flickering... Any help will be grand. Thanks.

Also. If its any help theres a map fragment behind the Activity A recycler view if its any help.

Upvotes: 0

Views: 1759

Answers (1)

VladimirVip
VladimirVip

Reputation: 404

Does setting android:windowSharedElementsUseOverlay (inside your Activity's XML theme file) to false solve your problem?

Upvotes: 4

Related Questions