I have a recyclerView, that contains a list of custom views. When I click a recyclerView item, it is expanded, providing more information. Another click upon this view (or upon another one) closes current one. The default animation, that provides SimpleItemAnimator, doesn't appear to be suitable. So, I tried to implement animateChange on my own like this:
public class CustomItemAnimator extends CustomDefaultItemAnimator {
    private static final int FADE_IN = 1;
    private static final int FADE_OUT = 2;
    private ItemHolderInfo getItemHolderInfo(RecyclerView.ViewHolder viewHolder, MoveInfo moveInfo) {
        moveInfo.stuff.clear();
        ViewGroup content_container = (ViewGroup) viewHolder.itemView.findViewById(R.id.item_content);
        for (int i = 0; i < content_container.getChildCount(); i++) {
            View view = content_container.getChildAt(i);
            if (view.getVisibility() == View.VISIBLE) {
                moveInfo.stuff.put(view.getId(), new Pair<>(view.getTop(), view.getBottom()));
            }
        }
        moveInfo.stuff.put(viewHolder.itemView.getId(), new Pair<>(viewHolder.itemView.getTop(), viewHolder.itemView.getBottom()));
        moveInfo.stuff.put(content_container.getId(), new Pair<>(content_container.getTop(), content_container.getBottom()));
        return moveInfo;
    }
    @NonNull
    @Override
    public ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state, @NonNull RecyclerView.ViewHolder viewHolder, int changeFlags, @NonNull List<Object> payloads) {
        ItemHolderInfo info = super.recordPreLayoutInformation(state, viewHolder, changeFlags, payloads);
        return getItemHolderInfo(viewHolder, (MoveInfo) info);
    }
    @NonNull
    @Override
    public ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state, @NonNull RecyclerView.ViewHolder viewHolder) {
        MoveInfo info = (MoveInfo) super.recordPostLayoutInformation(state, viewHolder);
        return getItemHolderInfo(viewHolder, info);
    }
    @Override
    public boolean animateChange(@NonNull final RecyclerView.ViewHolder oldHolder, @NonNull final RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
        Log.d("ANIMATOR", "animate change called 2");
        MoveInfo pre = (MoveInfo) preInfo;
        MoveInfo post = (MoveInfo) postInfo;
        int fade_style;
        final HashMap<Integer, Pair<Integer, Integer>> minMap;
        HashMap<Integer, Pair<Integer, Integer>> maxMap;
        if (pre.stuff.keySet().size() <= post.stuff.keySet().size()) {
            minMap = pre.stuff;
            maxMap = post.stuff;
            fade_style = FADE_IN;
        } else {
            minMap = post.stuff;
            maxMap = pre.stuff;
            fade_style = FADE_OUT;
        }
        /*Getting the GoneViews*/
        HashMap<Integer, Pair<Integer, Integer>> goneViews = new HashMap<>();
        for (Integer i : maxMap.keySet()) {
            if (minMap.get(i) == null) {
                goneViews.put(i, maxMap.get(i));
            }
        }
        List<Animator> animators = new ArrayList<>();
        for (Integer i : minMap.keySet()) {
            ViewPropertyAnimatorCompat animView = ViewCompat.animate(newHolder.itemView.findViewById(i));
            ObjectAnimator viewDeltaTop = ObjectAnimator.ofInt(newHolder.itemView.findViewById(i), "top", pre.stuff.get(i).first, post.stuff.get(i).first);
            ObjectAnimator viewDeltaBot = ObjectAnimator.ofInt(newHolder.itemView.findViewById(i), "bottom", pre.stuff.get(i).second, post.stuff.get(i).second);
            animators.add(viewDeltaTop);
            animators.add(viewDeltaBot);
        }
        for (Integer i : goneViews.keySet()) {
            float from = fade_style == FADE_IN ? 0.0f : 1.0f;
            float to = fade_style == FADE_IN ? 1.0f : 0.0f;
            Animator viewAlpha = ObjectAnimator.ofFloat(newHolder.itemView.findViewById(i), "alpha", from, to);
            animators.add(viewAlpha);
        }
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.playTogether(animators);
        animatorSet.setDuration(getChangeDuration());
        animatorSet.start();
        return true;
    }
    @Override
    public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, @NonNull List<Object> payloads) {
        //to make viewholders reusable
        return true;
    }
    //we store our infos here
    private class MoveInfo extends ItemHolderInfo {
        HashMap<Integer, Pair<Integer, Integer>> stuff = new HashMap<>();
    }
    //not implementing this cause cast error in my case
    @Override
    public ItemHolderInfo obtainHolderInfo() {
        return new MoveInfo();
    }
}
This works like a charm, except one thing. If I try to scroll, while changes are animated, the animated view is not displayed properly. It looks like as if the animated bottom/top values don't receive any input by  the scroll. I rly like the way, the itemAnimator works, and I would like to make things work at this way. Any tips are appreciated. Probably, I have to examine LinearLayoutManager?
 
    