Material Animations 4:Circular R

作者: SherlockShi | 来源:发表于2016-10-11 23:21 被阅读91次

    一、前言

    Circular Reveal Animations,官方称之为循环揭露动画效果,是一种用来显示/隐藏一组UI界面元素的动画效果,它是在API 21引入的,对应的类是ViewAnimationUtils

    循环揭露动画效果可以和共享元素变换动画组合,用来创造一些有意义的动画效果,自然地告诉用户这个app有些什么东西,将会产生怎样的效果。

    二、效果图

    三、实现

    在上面的例子中,依次发生了:

    • 橘色的圆是一个共享元素,从MainActivity变换到CircularRevealActivity
    • CircularRevealActivity中有一个监听器(listener),用来监听共享元素转换动画的结束,当动画结束时,做了这么两件事:
      • 为Toolbar执行了一个循环揭露动画
      • CircularRevealActivity中的视图(Views)执行了一个放大动画,使用的是以前的ViewPropertyAnimator

    监听共享元素进入动画的结束

    Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
    getWindow().setSharedElementEnterTransition(transition);
    transition.addListener(new Transition.TransitionListener() {
        @Override
        public void onTransitionEnd(Transition transition) {
            animateRevealShow(mToolbar);
            animateButtonsIn();
        }
        ...
    });
    

    animateRevealShow(mToolbar)

    private void animateRevealShow(View viewRoot) {
        int centerX = (viewRoot.getLeft() + viewRoot.getRight()) / 2;
        int centerY = (viewRoot.getTop() + viewRoot.getBottom()) / 2;
        int endRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight());
            
        Animator animator = ViewAnimationUtils.createCircularReveal(viewRoot, centerX, centerY, 0, endRadius);
        viewRoot.setVisibility(View.VISIBLE);
        animator.setDuration(1000);
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
    }
    

    上述方法的重点是createCircularReveal (View view, int centerX, int centerY, float startRadius, float endRadius)
    view:要执行循环揭露动画的View
    centerX:循环揭露动画中心位置的X坐标
    centerY:循环揭露动画中心位置的Y坐标
    startRadius:循环揭露动画的起始半径
    endRadius:循环揭露动画的结束半径

    animateButtonsIn()

    private void animateButtonsIn() {
        for (int i = 0; i < bgViewGroup.getChildCount(); i++) {
            View child = bgViewGroup.getChildAt(i);
            child.animate()
                    .setStartDelay(100 + i*DELAY)
                    .setInterpolator(interpolator)
                    .alpha(1)
                    .scaleX(1)
                    .scaleY(1);
        }
    }
    

    上述方法为底部的4个圆执行了一个放大动画,使用ViewPropertyAnimator类。

    四、更多

    还有一些不同的方式来创建循环揭露动画,关键是使用动画效果让用户更好地理解这个app有些什么东西,将会产生怎样的效果。

    1. 从目标视图的中心创建循环揭露动画

    public void revealGreenAtMiddle(View view) {
        int centerX = (bgViewGroup.getLeft() + bgViewGroup.getRight()) / 2;
        int centerY = (bgViewGroup.getTop() + bgViewGroup.getBottom()) / 2;
        int endRadius = (int) Math.hypot(bgViewGroup.getWidth()/2, bgViewGroup.getHeight()/2);
    
        Animator animator = ViewAnimationUtils.createCircularReveal(bgViewGroup, centerX, centerY, 0, endRadius);
        bgViewGroup.setBackgroundResource(R.color.green);
        animator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();
    }
    

    2. 从目标视图的顶部创建循环揭露动画+底部按钮动画

    public void revealBlueAtTop(View view) {
        animateButtonsOut();
    
        int centerX = (bgViewGroup.getLeft() + bgViewGroup.getRight()) / 2;
        int centerY = 0;
        int endRadius = (int) Math.hypot(bgViewGroup.getWidth()/2, bgViewGroup.getHeight());
    
        Animator animator = ViewAnimationUtils.createCircularReveal(bgViewGroup, centerX, centerY, 0, endRadius);
        bgViewGroup.setBackgroundResource(R.color.blue);
        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationEnd(Animator animation) {
                animateButtonsIn();
            }
            ...
        });
        animator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();
    }
    

    此处动画效果经历了以下3个步骤:

    • 隐藏底部按钮(通过控制按钮的透明度、缩放比例)
    • 从顶部执行循环揭露动画
    • 监听器监听到揭露动画执行完后,显示底部按钮(还是通过控制按钮的透明度、缩放比例)

    3. 在点击位置创建循环揭露动画

    首先,给橘色圆添加触摸监听事件,获取点击到的橘色圆的位置坐标:

    findViewById(R.id.iv_square_orange).setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (v.getId() == R.id.iv_square_orange) {
                revealOrangeAtPoint(event.getRawX(), event.getRawY());
            }
            return false;
        }
    });
    

    接着,就跟前面一样了,根据获取到的坐标位置创建循环揭露动画:

    private void revealOrangeAtPoint(float rawX, float rawY) {
        int centerX = (int) rawX;
        int centerY = (int) rawY;
        int endRadius = (int) Math.hypot(bgViewGroup.getWidth(), bgViewGroup.getHeight());
    
        Animator animator = ViewAnimationUtils.createCircularReveal(bgViewGroup, centerX, centerY, 0, endRadius);
        bgViewGroup.setBackgroundResource(R.color.orange);
        animator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
        animator.setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();
    }
    

    4. 属性变化动画+循环揭露动画

    这个会难那么一丢丢,毕竟是两个动画效果的组合技,但是只要抓住上一篇讲的属性变化动画和上面讲的循环揭露动画这两个点,就不难理解了。

    private void revealRedAtCenter() {
        final ViewGroup.LayoutParams originalParams = ivSquareRed.getLayoutParams();
        
        Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
        transition.addListener(new Transition.TransitionListener() {
            @Override
            public void onTransitionEnd(Transition transition) {
                int centerX = (bgViewGroup.getLeft() + bgViewGroup.getRight()) / 2;
                int centerY = (bgViewGroup.getTop() + bgViewGroup.getBottom()) / 2;
                int endRadius = (int) Math.hypot(bgViewGroup.getWidth(), bgViewGroup.getHeight());
        
                Animator animator = ViewAnimationUtils.createCircularReveal(bgViewGroup, centerX, centerY, 0, endRadius);
                bgViewGroup.setBackgroundResource(R.color.red);
                animator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
                animator.setInterpolator(new AccelerateDecelerateInterpolator());
                animator.start();
        
                ivSquareRed.setLayoutParams(originalParams);
            }
            ...
        });
        
        TransitionManager.beginDelayedTransition(bgViewGroup, transition);
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT);
        ivSquareRed.setLayoutParams(params);
    }
    

    五、总结

    本篇的重点就1个内容:
    createCircularReveal (View view, int centerX, int centerY, float startRadius, float endRadius)

    只要抓住这两条主线,其它的内容都可以按主线来抽丝拨茧,一切难题都可以迎刃而解。

    项目代码已分享到Github:https://github.com/SherlockShi/AndroidMaterialAnimationPractise

    六、参考资料

    Material Animations

    PS:欢迎关注SherlockShi博客

    相关文章

      网友评论

        本文标题:Material Animations 4:Circular R

        本文链接:https://www.haomeiwen.com/subject/lkobyttx.html