【问题标题】:Animating shared element transitions using android fragments seems to be a nightmare使用android片段动画共享元素过渡似乎是一场噩梦
【发布时间】:2026-02-08 21:05:02
【问题描述】:

动画两个片段之间的共享元素过渡似乎很痛苦。我让它在我的应用程序的其他地方使用完全相同的代码工作。

这是我在 recyclerview 适配器中的点击代码:

private void click(int position, ItemViewHolder holder){

final ItemDescription itemDescription = itemListFiltered.get(position);
FragmentManager fm = mContext.getSupportFragmentManager();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && itemDescription != null) {

    //animate transition
    TransitionSet transitionSet = new TransitionSet();
    transitionSet.addTransition(new ChangeTransform());
    transitionSet.addTransition(new ChangeBounds());
    transitionSet.addTransition(new ChangeImageTransform());
    transitionSet.setDuration(300);

    //set up fragment
    ScanDetailsFragment frag = ScanDetailsFragment.newInstance(itemDescription, holder.productImage.getTransitionName());
    frag.setEnterTransition(transitionSet);
    frag.setExitTransition(transitionSet);

    fm.beginTransaction().replace(R.id.fragment_container, frag)
            .addSharedElement(holder.productImage, "product_image")
            .addToBackStack("item details")
            .commit();
}else {
    ScanDetailsFragment itemDetails = ScanDetailsFragment.newInstance(itemDescription);
    fm.beginTransaction().replace(R.id.fragment_container, itemDetails).addToBackStack("item details").commit();
}

我似乎无法让这个动画工作。

【问题讨论】:

    标签: java android android-fragments android-animation android-recyclerview


    【解决方案1】:

    这是我的做法

    带有 RecyclerView 的片段

    public class DogFragment extends Fragment implements DogAdapter.OnItemCLickListener {
    
        public static final String TAG = "DogFragment";
    
        @InjectView(R.id.recyclerview_dog)
        RecyclerView mRecyclerView;
    
        DogAdapter adapter;
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            super.onCreateView(inflater, container, savedInstanceState);
            final View v = inflater.inflate(R.layout.fragment_dog, container, false);
            ButterKnife.inject(this, v);
            return v;
        }
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            final List<Integer> images = new ArrayList<>();
            images.add(R.drawable.dog1);
            images.add(R.drawable.dog2);
            images.add(R.drawable.dog3);
    
            final RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 1);
            mRecyclerView.setLayoutManager(layoutManager);
            adapter = new DogAdapter(images);
            adapter.setOnItemClickListener(this);
            mRecyclerView.setAdapter(adapter);
        }
    
        public String getTAG() {
            return TAG;
        }
    
        @Override
        public void onItemClick(int position, int imageRefId, ImageView imageView) {
            SingleDogFragment fragment = SingleDogFragment.getInstance(getActivity(), adapter.getImageTransitionName(getActivity(), position), imageRefId);
            getFragmentManager().beginTransaction()
                    .addSharedElement(imageView, adapter.getImageTransitionName(getActivity(), position))
                    .replace(R.id.container, fragment, fragment.getTag())
                    .addToBackStack(null)
                    .commit();
        }
    }
    

    适配器

    public class DogAdapter extends RecyclerView.Adapter<DogAdapter.ViewHolder> {
    
        private OnItemCLickListener mItemClickListener;
        private List<Integer> mImages;
    
        public DogAdapter(List<Integer> images) {
            mImages = images;
        }
    
        public int getItem(int position) {
            return mImages.get(position);
        }
    
        @Override
        public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.gridview_element_dog, viewGroup, false);
    
            return new ViewHolder(v);
        }
    
        @Override
        public void onBindViewHolder(ViewHolder viewHolder, int i) {
            viewHolder.mImageView.setImageResource(getItem(i));
            viewHolder.mImageView.setTransitionName(
                    getImageTransitionName(viewHolder.mImageView.getContext(), i)
            );
        }
    
        public String getImageTransitionName(Context context, int position) {
            return context.getString(R.string.dog_transition_name) + position;
        }
    
        @Override
        public int getItemCount() {
            return mImages.size();
        }
    
        public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    
            @InjectView(R.id.dog_imageview)
            ImageView mImageView;
    
            public ViewHolder(final View view) {
                super(view);
                ButterKnife.inject(this, view);
                view.setOnClickListener(this);
            }
    
            @Override
            public void onClick(View v) {
                if (mItemClickListener != null) {
                    mItemClickListener.onItemClick(getPosition(), getItem(getPosition()), mImageView);
                }
            }
        }
    
        public interface OnItemCLickListener {
            public void onItemClick(int position, int refId, ImageView imageView);
        }
    
        public void setOnItemClickListener(final OnItemCLickListener mItemClickListener) {
            this.mItemClickListener = mItemClickListener;
        }
    
    }
    

    目标片段

    public class SingleDogFragment extends Fragment {
    
        private static final String ARG_TRANSITION_NAME = "ARG_TRANSITION_NAME";
        private static final String ARG_IMAGE_REF_ID = "ARG_IMAGE_REF_ID";
    
        @InjectView(R.id.single_dog_imageview)
        ImageView mDogImage;
    
        public static SingleDogFragment getInstance(Context context, String transitionName, int imageRefId) {
            SingleDogFragment fragment = new SingleDogFragment();
            Bundle bundle = new Bundle();
            bundle.putString(ARG_TRANSITION_NAME, transitionName);
            bundle.putInt(ARG_IMAGE_REF_ID, imageRefId);
            fragment.setSharedElementEnterTransition(TransitionInflater.from(context).inflateTransition(R.transition.change_transform));
            fragment.setEnterTransition(TransitionInflater.from(context).inflateTransition(R.transition.slide_left));
            fragment.setExitTransition(TransitionInflater.from(context).inflateTransition(R.transition.slide_left));
            fragment.setArguments(bundle);
            return fragment;
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            super.onCreateView(inflater, container, savedInstanceState);
            View v = inflater.inflate(R.layout.fragment_single_dog, container, false);
            ButterKnife.inject(this, v);
            mDogImage.setTransitionName(getArguments().getString(ARG_TRANSITION_NAME));
            mDogImage.setImageResource(getArguments().getInt(ARG_IMAGE_REF_ID));
            return v;
        }
    }
    

    change_transform.xml

    <?xml version="1.0" encoding="utf-8"?>
    <transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
        <targets>
            <target android:excludeId="@android:id/statusBarBackground"/>
            <target android:excludeId="@android:id/navigationBarBackground"/> <!-- exclude the status bar and the navigation bar of the animation -->
        </targets>
        <changeBounds/>
        <changeTransform/>
    </transitionSet>
    

    这就是它的样子

    希望我能帮上忙!

    【讨论】:

    • 你能发布 slide_left 过渡吗?