Custom fragment transition parent-to-child navigation setExitTransition not showing
Asked Answered
P

0

0

Background

I've been trying to get parent-to-child navigational transition implemented (specifically for recyclerview items -> detail fragment). I'm currently using sharedElementTransitions with the item container and detail container as the sharedElement along with ChangeTransform and ChangeBounds transitions. The detail fragment's enter transition is mostly working. However, I am having problems with the recyclerview item's exit transition. What I want to do is have the recyclerview dim/turn darker while the detail view expands to full screen. When I try to use a custom transition, the exit transition never animates. Instead, the detail view is immediately shown and its enter transition animates.

Transition problem

As you can see, the recyclerview fragment is hidden before the exit animation is played. I need the recyclerview to be shown with the dimming effect while the detail view is expanding.

Problem

How do I get the dim custom exit transition to play while the detail enter transition is also playing?

What I've tried

  • setDelay - setDelay on detail enter transition. The transition is delayed but the detail fragment immediately shown (the recyclerview is blocked off by the new fragment).
  • setDuration - setDuration on recyclerview exit transition. Detail fragment still blocks the recyclerview.

ItemViewModel.java

public void displayArticle(View view) {

    MainActivity mainActivity = (MainActivity) view.getContext();
    ArticleFragment detailsFragment = ArticleFragment.newInstance(article.getValue(), transitionName.getValue());
    ArticleListingFragment itemFragment = (ArticleListingFragment) mainActivity.getSupportFragmentManager().findFragmentByTag(ArticleListingFragment.TAG);

    doOpenArticleTransition(detailsFragment, itemFragment);

    mainActivity.getSupportFragmentManager()
            .beginTransaction()
            .addSharedElement(view.findViewById(R.id.article_entry), transitionName.getValue())
            .replace(R.id.main_content_container, detailsFragment)
            .addToBackStack(null)
            .commit();
}

private void doOpenArticleTransition(Fragment newFragment, Fragment oldFragment) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        Transition openArticleTransition = TransitionInflater.from(oldFragment.getContext()).inflateTransition(R.transition.transition_article);
        newFragment.setSharedElementEnterTransition(openArticleTransition);
        newFragment.setEnterTransition(new Fade());
        oldFragment.setExitTransition(new Dim(oldFragment.getContext()));
        newFragment.setSharedElementReturnTransition(openArticleTransition);
    }
}

Dim.java

public class Dim extends BaseTransition {

private static final String PROPNAME_BACKGROUND = "meridian:dim:background";
private final Context context;

public Dim(Context context) {
    this.context = context;
}

public Dim(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
}

@Override
public void captureValues(TransitionValues transitionValues) {
    Drawable background = transitionValues.view.getBackground();
    transitionValues.values.put(PROPNAME_BACKGROUND, background);
}

@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
    final View view;
    if (startValues == null && endValues != null) {
        view = endValues.view;
    } else {
        view = startValues.view;
    }

    int whiteBackground = ContextCompat.getColor(context, R.color.white);
    int grayBackground = ContextCompat.getColor(context, R.color.gray700);
    ValueAnimator animator = ValueAnimator.ofArgb(whiteBackground, grayBackground);
    animator.setDuration(400);
    animator.setStartDelay(300);
    animator.addUpdateListener(animation -> view.setBackgroundColor((Integer)animation.getAnimatedValue()));
    return animator;
}
}

transition_article.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="together">
    <changeBounds/>
    <changeTransform/>
    <transition 
    class="meridian.custom.anim.Elevate"/>
</transitionSet>

recyclerview_item.xml

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/article_entry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground">

<TextView
    android:id="@+id/article_listing_section"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/two_line_list_entry_margin_lr"
    android:layout_marginEnd="@dimen/two_line_list_entry_margin_lr"
    android:layout_marginTop="@dimen/two_line_list_entry_margin_tb"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toStartOf="@id/article_listing_section_title_barrier"
    app:layout_constraintTop_toTopOf="parent"
    style="@style/EntryOverline"
    tools:text="@tools:sample/cities" />

<TextView
    android:id="@+id/article_listing_date"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/two_line_list_entry_margin_tb"
    android:layout_marginEnd="@dimen/two_line_list_entry_margin_lr"
    android:textAlignment="viewEnd"
    app:layout_constraintEnd_toStartOf="@+id/article_listing_date_image_barrier"
    app:layout_constraintTop_toTopOf="parent"
    style="@style/EntryOverlineGray"
    tools:text="17h" />

<TextView
    android:id="@+id/article_listing_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginBottom="@dimen/two_line_list_entry_margin_tb"
    android:layout_marginEnd="@dimen/two_line_list_entry_margin_lr"
    android:layout_marginTop="@dimen/two_line_list_entry_first_line_second_line_spacing"
    app:layout_constraintStart_toStartOf="@id/article_listing_section"
    app:layout_constraintEnd_toStartOf="@id/article_listing_section_title_barrier"
    app:layout_constraintTop_toBottomOf="@id/article_listing_section"
    app:layout_constraintBottom_toBottomOf="parent"
    android:minLines="3"
    android:maxLines="3"
    style="@style/EntrySubtitle1"
    tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." />

<ImageView
    android:id="@+id/article_listing_image"
    android:layout_width="@dimen/two_line_list_entry_image_width"
    android:layout_height="@dimen/two_line_list_entry_image_width"
    android:layout_marginStart="@dimen/two_line_list_entry_margin_lr"
    android:layout_marginEnd="@dimen/two_line_list_entry_margin_lr"
    android:contentDescription="@string/content_description_image_article_entry"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toEndOf="@+id/article_listing_date_image_barrier"
    app:layout_constraintTop_toTopOf="parent"
    android:src="@drawable/item_article_entry_image_placeholder" />

<android.support.constraint.Barrier
    android:id="@+id/article_listing_section_title_barrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="start"
    app:constraint_referenced_ids="article_listing_date"/>

<android.support.constraint.Barrier
    android:id="@+id/article_listing_date_image_barrier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:barrierDirection="start"
    app:constraint_referenced_ids="article_listing_image"/>

</android.support.constraint.ConstraintLayout> 

recyclerview_fragment.xml

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_article_sections"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinator_layout_articles"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/toolbar" />

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipe_to_refresh_articles"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/articles"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:itemCount="2"
            tools:layoutManager="android.support.v7.widget.LinearLayoutManager"
            tools:listitem="@layout/item_article_entry" />

    </android.support.v4.widget.SwipeRefreshLayout>

</android.support.design.widget.CoordinatorLayout>

<android.support.design.widget.NavigationView
    android:id="@+id/navigation_view_article_sections"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:itemTextAppearance="@style/SectionSubtitle1"
    app:menu="@menu/navigation_article_topic"
    app:headerLayout="@layout/navigation_header_article_sections"/>

details_fragment.xml

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:elevation="24dp">

<include
    layout="@layout/toolbar" />

<android.support.v4.widget.NestedScrollView
    android:id="@+id/article_scroll_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/article"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:context=".ui.article.display.ArticleFragment">

        <HorizontalScrollView
            android:id="@+id/article_description_scroll_container"
            style="@style/HorizontalChipScroller"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:scrollbars="none"
            android:visibility="gone"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

            <android.support.design.chip.ChipGroup
                android:id="@+id/article_description_chip_group"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:contentDescription="@string/chip_group_description_tags"
                app:singleLine="true"/>

        </HorizontalScrollView>

        <ImageView
            android:id="@+id/article_image"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="16dp"
            android:layout_marginEnd="@dimen/detail_general_margin_lr"
            android:layout_marginStart="@dimen/detail_general_margin_lr"
            android:layout_marginTop="@dimen/detail_general_margin_tb"
            android:contentDescription="@string/content_description_image_article"
            android:scaleType="centerCrop"
            android:src="@drawable/item_article_entry_image_placeholder"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHeight_percent="0.45"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/article_description_scroll_container"
            tools:layout_height="208dp"
            tools:src="@color/colorImagePlaceholder" />

        <TextView
            android:id="@+id/article_section"
            style="@style/DetailOverline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginEnd="@dimen/detail_general_margin_lr"
            android:layout_marginStart="@dimen/detail_general_margin_lr"
            android:layout_marginTop="@dimen/detail_general_margin_tb"
            app:layout_constraintEnd_toStartOf="@id/article_subsection"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/article_image"
            tools:text="US"
            tools:textColor="@color/gray900" />

        <TextView
            android:id="@+id/article_subsection"
            style="@style/DetailOverline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/detail_general_margin_lr"
            android:layout_marginTop="@dimen/detail_general_margin_tb"
            app:layout_constraintStart_toEndOf="@id/article_section"
            app:layout_constraintTop_toBottomOf="@id/article_image"
            tools:text="Poverty"
            tools:textColor="@color/gray900" />

        <TextView
            android:id="@+id/article_title"
            style="@style/DetailH6Headline"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/detail_general_margin_tb"
            android:layout_marginEnd="@dimen/detail_general_margin_lr"
            android:layout_marginStart="@dimen/detail_general_margin_lr"
            android:layout_marginTop="8dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/article_section"
            tools:text="Pope Accepts Wuerl's Resignation as Washington Archbishop, but Calls Him a Model Bishop"
            tools:textColor="@color/gray900"
            tools:textSize="20sp"
            tools:textStyle="bold" />

        <TextView
            android:id="@+id/article_abstract"
            style="@style/DetailBody2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/detail_general_margin_tb"
            android:layout_marginEnd="@dimen/detail_general_margin_lr"
            android:layout_marginStart="@dimen/detail_general_margin_lr"
            android:layout_marginTop="@dimen/detail_general_margin_tb"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/article_title"
            tools:text="Despite demands to oust Cardinal Wuerl over sexual abuse scandals, Pope Francis praised him as a model leader."
            tools:textColor="@color/gray600" />

        <TextView
            android:id="@+id/article_author"
            style="@style/DetailBody1"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/detail_general_margin_tb"
            android:layout_marginEnd="@dimen/detail_general_margin_lr"
            android:layout_marginStart="@dimen/detail_general_margin_lr"
            android:layout_marginTop="@dimen/detail_general_margin_tb"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/article_abstract"
            tools:text="by Jason Horowitz, Elizabeth Dias and Laurie Goodstein"
            tools:textColor="@color/gray900" />

        <android.support.design.button.MaterialButton
            android:id="@+id/article_full_content_button"
            style="@style/OutlinedButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/detail_general_margin_tb"
            android:layout_marginEnd="@dimen/detail_general_margin_lr"
            android:layout_marginStart="@dimen/outlined_button_padding_lr"
            android:layout_marginTop="@dimen/detail_general_margin_tb"
            android:text="@string/button_label_article_read_more"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/article_author" />

    </android.support.constraint.ConstraintLayout>
</android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>

DetailsFragment.java

@BindView(R.id.article)
ConstraintLayout container;

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    setupToolbar();
    setTransitionName();
    loadArticle();
}

private void setTransitionName() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        container.setTransitionName(this.getArguments().getString(ARG_TRANSITION));
    }
}
Phosphoprotein answered 27/10, 2018 at 22:12 Comment(5)
What is the BaseTransition class?Koser
Its just a wrapper for the Transition class. All it contains is an abstract captureValues method.Phosphoprotein
Do you call Transition.addSharedElement anywhere? And seems that you haven't defined the targets to your shared element transition. Note that to make shared element yours transition you should only animate recyclerview's item background. And every of your items in recyclerview should have different transition name. So in your case you at least need to call transition.addSharedElement(<your recyclerview's item>, <transition name of Coordinator Layout in your details fragment>)Koser
I call transaction.addSharedElement in doOpenArticlesTransition(). You can see it in ItemViewModel.java above. By defining targets, do you mean setting the transitionname? I do that in the onViewCreated() method of details fragment. The transitionname should be different since I use a constant + article.title as the name where each title is different.Phosphoprotein
I don't sure, but maybe the problem is in doOpenArticleTransition method, in this line: > newFragment.setEnterTransition(new Fade()); . As I understand, the fade animation is applied to every view in the fragment. How about to create another transition (via code or xml) and to set there targets to exclude shared views?Koser

© 2022 - 2024 — McMap. All rights reserved.