首页 > 解决方案 > 返回共享元素的动画不起作用

问题描述

我在 Fragment A 中创建了一个 recyclerview,单击一个元素会打开第二个片段,其中从一个 oage 到另一个 oage 的图像应该动画。进入动画工作正常,但退出动画不起作用。片段是使用 NavigationEditor 添加的。

这是代码:

RecyclerView 片段 ->

public class SightSeeingFragment extends Fragment {

    RecyclerView sightSeeingRv;
    ArrayList<Place> placeArrayList;
    SightSeeingAdapter sightSeeingAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        postponeEnterTransition();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_sight_seeing, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        postponeEnterTransition();
        init(view);
    }

    private void init(View view) {
        sightSeeingRv = view.findViewById(R.id.sight_seeing_rv);
        setRecyclerView();
    }

    private void setRecyclerView() {
        new SetRecyclerView().execute();
    }

    class SetRecyclerView extends AsyncTask<Void, Void, Void> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
            sightSeeingRv.setLayoutManager(linearLayoutManager);
        }

        @Override
        protected Void doInBackground(Void... voids) {
            placeArrayList = new Gson().fromJson(placesToVisit,
                    new TypeToken<List<Place>>() {
                    }.getType());
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (sightSeeingAdapter == null)
                sightSeeingAdapter = new SightSeeingAdapter(getContext(), placeArrayList);
            sightSeeingRv.setAdapter(sightSeeingAdapter);
           sightSeeingRv.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                startPostponedEnterTransition();
                return true;
            }
        });
        }
    }
}

适配器 ->

public class SightSeeingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    Context context;
    ArrayList<Place> placeArrayList;
    public SightSeeingAdapter(Context context, ArrayList<Place> placeArrayList) {
        this.context = context;
        this.placeArrayList = placeArrayList;
        if(this.placeArrayList == null)
            placeArrayList = new ArrayList<>();
    }

    @Override
    public int getItemViewType(int position) {
        if(position == 0)
            return 0;
        else return 1;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if(viewType == 0)
        {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.sightseeing_row_0, parent, false);
            return new SightSeeingTextViewHolder(view);
        }else
        {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.row_sight_seeing, parent, false);
        return new SightSeeingViewHolder(view);
    }}

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if(position!=0) {
            ((SightSeeingViewHolder)holder).bindView(position-1);
        }
    }

    @Override
    public int getItemCount() {
        return placeArrayList.size()+1;
    }

    class SightSeeingTextViewHolder extends RecyclerView.ViewHolder {

        public SightSeeingTextViewHolder(@NonNull View itemView) {
            super(itemView);
        }
    }
    class SightSeeingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView nameOfPlace;
        TextView descOfPlace;
        ImageView imageOfPlace;
        CardView placeRow;
        int position;
        public SightSeeingViewHolder(@NonNull View itemView) {
            super(itemView);
            nameOfPlace = itemView.findViewById(R.id.name_of_place);
            descOfPlace = itemView.findViewById(R.id.desc_of_place);
            imageOfPlace = itemView.findViewById(R.id.image_of_place);
            placeRow = itemView.findViewById(R.id.place_row);
        }

        public void bindView(int position) {
            Place place = placeArrayList.get(position);
            this.position = position;
            nameOfPlace.setText(place.getNameOfPlace());
            descOfPlace.setText(place.getShortDescription());
            placeRow.setTag(position);
            placeRow.setOnClickListener(this);
            Glide.with(context).load(Utils.getDrawableImage(place.getImage(),context)).into(imageOfPlace);
            ViewCompat.setTransitionName(imageOfPlace, position+"");
        }

        @Override
        public void onClick(View view) {
            int position = (int) view.getTag();
            FragmentNavigator.Extras extras = new FragmentNavigator.Extras.Builder()
                    .addSharedElement(imageOfPlace,position+"").build();
            Navigation.findNavController(view)
                    .navigate(SightSeeingFragmentDirections.actionNavigationSightseeingToPlaceholder()
                            .setPlaceDetail(placeArrayList.get(position)).setTransitionName(position+""),extras);
        }
    }
}

片段 B ->

public class DetailOfPlaceFragment extends Fragment implements View.OnClickListener {

    Place place;
    ImageView placeImage;
    TextView placeDetails;
    Button checkTheLocation;
    String transitionName;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        postponeEnterTransition();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_detail_of_place, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        place = DetailOfPlaceFragmentArgs.fromBundle(getArguments()).getPlaceDetail();
        transitionName = DetailOfPlaceFragmentArgs.fromBundle(getArguments()).getTransitionName();
        init(view);
    }

    private void init(View view) {
        placeImage = view.findViewById(R.id.place_image);
        placeDetails = view.findViewById(R.id.place_details);
        checkTheLocation = view.findViewById(R.id.check_the_location);
        checkTheLocation.setOnClickListener(this);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            placeImage.setTransitionName(transitionName);
        }
        Glide.with(getContext()).load(Utils.getDrawableImage(place.getImage(),getContext())).listener(new RequestListener<Drawable>() {
            @Override
            public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                startPostponedEnterTransition();
                return false;
            }

            @Override
            public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                startPostponedEnterTransition();
                return false;
            }
        }).into(placeImage);
        placeDetails.setText(place.getDescription());
    }

    @Override
    public void onClick(View view) {
        String url = String.format(getString(R.string.maps_url),place.getLatOnMap()+"",
                place.getLondOnMap()+"",place.getNameOfPlace());
        Utils.openActionIntent(url,getContext());
    }
}

由于延迟动画,进入动画也不是很流畅。但这是次要问题。

标签: androidandroid-fragmentsandroid-jetpack

解决方案


您的 RecyclerView 片段还需要使用postponeEnterTransition()and startPostponedEnterTransition():它的视图将被销毁,当它被放入后堆栈并且不推迟转换时,共享元素转换将尝试在您AsyncTask实际完成RecyclerView重新填充数据之前发生,导致到没有可以返回的视图。

将共享元素转换添加到 GithubBrowserSample的拉取请求是查找所有需要更改的移动部分的好地方。


推荐阅读