I'm trying to implement this
like others before me.
What I find so far:
- How to implement the "parent-to-child" navigational transition as prescribed by Material Design
- Material Design parent-child navigational transition recyclerview entry to detail fragment
- How to create Parent-child transition in which list item lifts out and become details screen
- Custom fragment transition parent-to-child navigation setExitTransition not showing
- https://medium.com/@bherbst/fragment-transitions-with-shared-elements-7c7d71d31cbb
- https://medium.com/@jim.zack.hu/android-inbox-material-transitions-for-recyclerview-71fc7326bcb5
- https://github.com/saket/InboxRecyclerView
- https://www.youtube.com/watch?v=EjTJIDKT72M
What I've so far:
Parent Fragment
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initViewModel();
setupRecyclerView();
initViewModelSubscriptions();
}
@Override
public void onClick(View v, CustomNavigator.Extras extras) {
Bundle bundle = new Bundle();
bundle.putString("transitionName", v.getTransitionName());
NavController navController = NavHostFragment.findNavController(this);
navController.navigate(R.id.action_devicemgmt_to_deviceMgmtEditFragment,
bundle, // Bundle of args
null, // NavOptions
extras);
}
Detail Fragment
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Transition t = TransitionInflater.from(getContext()).inflateTransition(R.transition.test).setDuration(1000);
setSharedElementEnterTransition(t);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setupToolbar();
setTransitionName();
}
private void setTransitionName() {
binding.coord.setTransitionName(getArguments().getString("transitionName"));
}
R.transition.test
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="together"
android:interpolator="@android:interpolator/fast_out_slow_in">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
</transitionSet>
ViewHolder of RecyclerView Adapter
static class BindingHolder extends RecyclerView.ViewHolder {
private final ItemDevicemgmtBinding binding;
BindingHolder(ItemDevicemgmtBinding binding) {
super(binding.getRoot());
this.binding = binding;
binding.getRoot().setOnClickListener(v -> {
CustomNavigator.Extras extras = new CustomNavigator.Extras.Builder()
.addSharedElement(v, v.getTransitionName())
.build();
callback.onClick(v, extras);
});
}
void bind(String deviceSn) {
binding.getRoot().setTransitionName(String.valueOf(getItemId()));
binding.setVariable(BR.deviceSn, deviceSn);
binding.executePendingBindings();
}
}
Parent Fragment Layout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_mgmt_devices"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.recyclerview.widget.RecyclerView>
<include
android:id="@+id/layout_mgmt_no_devices"
layout="@layout/layout_mgmt_no_devices"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/bottomappbar_height"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Detail Fragment Layout
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coord"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="New Item" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/const_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/design_default_color_primary">
<EditText
android:id="@+id/editText2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:ems="10"
android:inputType="textPersonName"
android:text="Serial Number"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
RecyclerView Item layout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:clickable="true"
android:focusable="true"
android:paddingStart="@dimen/single_line_item_padding_start"
android:paddingTop="@dimen/single_line_item_padding_top"
android:paddingEnd="@dimen/single_line_item_padding_end"
android:paddingBottom="@dimen/single_line_item_padding_bottom">
<TextView
android:id="@+id/text_devicemgmtitem_sn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:text="@{deviceSn}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/imagebutton_devicemgmtitem_more"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="89745897696978456790456456" />
</androidx.constraintlayout.widget.ConstraintLayout>
As you can see, the sharedEnterTransition is working but the reverse transition when leaving the Fragment is not what I have expected. Instead of fragments container the item container is transformed. Nick Butcher is talking about this transition in the video I linked in point 8 but unfortunately he only explains the collapse on scroll function. When I understood him right...
the idea..the previous content is still there..the new screen is lifted up and sitting on top of them
so at least its clear to have two seperate screens whereas the creator of InboxRecyclerView
is doing it in same layout.
But in Nick's example hes using Activities whereas I'm using Fragments so not sure if the replacement of Parent Fragment with Detail Fragment is a problem here?!
So can someone help me?