Android Shared Element Transition: Transforming an ImageView from a circle to a rectangle and back again

前端 未结 2 1223
小蘑菇
小蘑菇 2021-01-30 07:33

I\'m trying to do a shared element transition between two activities.

The first activity has a circle imageview and the second activity has a rectangular imageview. I ju

2条回答
  •  长情又很酷
    2021-01-30 07:49

    There's some code you need to add: basically you have to implement a custom transition. But most of the code can be reused. I'm going to push the code on github for your reference, but the steps needed are:

    SecondAcvitiy Create your custom transition:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    
        Transition transition = new CircularReveal();
        transition.setInterpolator(new LinearInterpolator());
    
        getWindow().setSharedElementEnterTransition(transition);
    }
    

    CircularReveal capture view bounds (start and end values) and provide two animations, the first one when you need to animate the circular image view to the big one, the second for the reverse case.

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public class CircularReveal extends Transition {
    
        private static final String BOUNDS = "viewBounds";
    
        private static final String[] PROPS = {BOUNDS};
    
        @Override
        public void captureStartValues(TransitionValues transitionValues) {
            captureValues(transitionValues);
        }
    
        @Override
        public void captureEndValues(TransitionValues transitionValues) {
            captureValues(transitionValues);
        }
    
        private void captureValues(TransitionValues values) {
            View view = values.view;
            Rect bounds = new Rect();
            bounds.left = view.getLeft();
            bounds.right = view.getRight();
            bounds.top = view.getTop();
            bounds.bottom = view.getBottom();
    
            values.values.put(BOUNDS, bounds);
        }
    
        @Override
        public String[] getTransitionProperties() {
            return PROPS;
        }
    
        @Override
        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
            if (startValues == null || endValues == null) {
                return null;
            }
    
            Rect startRect = (Rect) startValues.values.get(BOUNDS);
            final Rect endRect = (Rect) endValues.values.get(BOUNDS);
    
            final View view = endValues.view;
    
            Animator circularTransition;
            if (isReveal(startRect, endRect)) {
                circularTransition = createReveal(view, startRect, endRect);
                return new NoPauseAnimator(circularTransition);
            } else {
                layout(startRect, view);
    
                circularTransition = createConceal(view, startRect, endRect);
                circularTransition.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        view.setOutlineProvider(new ViewOutlineProvider() {
                            @Override
                            public void getOutline(View view, Outline outline) {
                                Rect bounds = endRect;
                                bounds.left -= view.getLeft();
                                bounds.top -= view.getTop();
                                bounds.right -= view.getLeft();
                                bounds.bottom -= view.getTop();
                                outline.setOval(bounds);
                                view.setClipToOutline(true);
                            }
                        });
                    }
                });
                return new NoPauseAnimator(circularTransition);
            }
        }
    
        private void layout(Rect startRect, View view) {
            view.layout(startRect.left, startRect.top, startRect.right, startRect.bottom);
        }
    
        private Animator createReveal(View view, Rect from, Rect to) {
    
            int centerX = from.centerX();
            int centerY = from.centerY();
            float finalRadius = (float) Math.hypot(to.width(), to.height());
    
            return ViewAnimationUtils.createCircularReveal(view, centerX, centerY,
                from.width()/2, finalRadius);
        }
    
        private Animator createConceal(View view, Rect from, Rect to) {
    
            int centerX = to.centerX();
            int centerY = to.centerY();
            float initialRadius = (float) Math.hypot(from.width(), from.height());
    
            return ViewAnimationUtils.createCircularReveal(view, centerX, centerY,
                initialRadius, to.width()/2);
        }
    
        private boolean isReveal(Rect startRect, Rect endRect) {
            return startRect.width() < endRect.width();
        }
    }
    

提交回复
热议问题