вот моя реализация.Существует FragmentList
с RecyclerView
с изображениями на каждом предмете.И есть FragmentDetail
только с большим изображением.Изображение из FragmentList
элемента списка перемещается в FragmentDetail
.TransitionName
анимированного представления на FragmentList
и FragmentDetail
должны совпадать.Поэтому я даю уникальное имя перехода для каждого элемента списка ImageView:
imageView.setTransitionName("anyString" + position)
Затем я передаю эту строку в FragmentDetail
через setArguments
и устанавливаю большое изображение transitionName
для этой строки,Также мы должны предоставить Transition
, который описывает, как анимация представления из одной иерархии представления в другую иерархию представления.После этого мы должны передать это transition
во фрагмент.Я делаю это до FragmentTransaction
:
detailFragment.setSharedElementEnterTransition(getTransition());
detailFragment.setSharedElementReturnTransition(getTransition());
Или вы можете переопределить getSharedElementEnterTransition
и getSharedElementReturnTransition
из Fragment
и объявить transition
там.Вот полный код:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new FragmentList())
.commit();
}
}
public void showDetail(View view) {
String transitionName = view.getTransitionName();
FragmentDetail fragment = new FragmentDetail();
fragment.setArguments(FragmentDetail.getBundle(transitionName));
fragment.setSharedElementEnterTransition(getTransition());
fragment.setSharedElementReturnTransition(getTransition());
getSupportFragmentManager()
.beginTransaction()
.addSharedElement(view, transitionName)
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
}
private Transition getTransition() {
TransitionSet set = new TransitionSet();
set.setOrdering(TransitionSet.ORDERING_TOGETHER);
set.addTransition(new ChangeBounds());
set.addTransition(new ChangeImageTransform());
set.addTransition(new ChangeTransform());
return set;
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" />
FragmentList:
public class FragmentList extends Fragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_list, container, false);
RecyclerView rv = view.findViewById(R.id.recyclerview);
rv.setAdapter(new ListAdapter());
return view;
}
private class ListAdapter extends RecyclerView.Adapter {
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
return new Holder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Holder hold = (Holder) holder;
hold.itemView.setOnClickListener(v -> {
((MainActivity) getActivity()).showDetail(hold.imageView);
});
//unique string for each list item
hold.imageView.setTransitionName("anyString" + position);
}
@Override
public int getItemCount() {
return 10;
}
private class Holder extends ViewHolder {
ImageView imageView;
public Holder(View view) {
super(view);
imageView = view.findViewById(R.id.image);
}
}
}
}
frag_list.xml
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
FragmentDetail:
public class FragmentDetail extends Fragment {
private static final String NAME_KEY = "key";
public static Bundle getBundle(String transitionName) {
Bundle args = new Bundle();
args.putString(NAME_KEY, transitionName);
return args;
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_detail, container, false);
String transitionName = getArguments().getString(NAME_KEY);
ImageView imageView = view.findViewById(R.id.image);
imageView.setTransitionName(transitionName);
return view;
}
}
frag_detail.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/image"
android:layout_width="300dp"
android:layout_height="300dp"
android:src="@drawable/cat"/>
</LinearLayout>
item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<ImageView
android:id="@+id/image"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/cat"/>
</LinearLayout>
Вот результат:
TransitionName
может быть любой строкой, которую вы хотите.Существует ViewCompat.setTransitionName
, если вам нужна поддержка устройств до Lollipop.