【Android -- 动画】CircularReveral 动画框架的基本使用

一、前言

这是 Android5.0 推出的新的动画框架,可以给 View 做一个揭露效果。效果如下:
在这里插入图片描述

二、Circular Reveal 介绍

当您显示或隐藏一组 UI 元素时,揭露动画可为用户提供视觉连续性。

ViewAnimationUtils.createCircularReveal() 方法让您能够为裁剪区域添加动画以揭露或隐藏视图。

/* @param view The View will be clipped to the animating circle.
   * @param centerX The x coordinate of the center of the animating circle, relative to
   *        <code view</code .
   * @param centerY The y coordinate of the center of the animating circle, relative to
   *        <code view</code .
   * @param startRadius The starting radius of the animating circle.
   * @param endRadius The ending radius of the animating circle.
   */
  public static Animator createCircularReveal(View view,
      int centerX, int centerY, float startRadius, float endRadius) {
    return new RevealAnimator(view, centerX, centerY, startRadius, endRadius);
  }

参数说明:

  • view :要执行动画效果的View
  • centerX:圆心x坐标
  • centerY:圆心y坐标
  • startRadius:开始时的圆半径
  • endRadius:结束时的圆半径

返回值是一个 Animator 。

ViewAnimationUtils.createCircularReveal() 方法所执行的效果,就是将一个 View 裁剪成圆,然后从圆心逐渐揭露展现视图。

三、实例

1. TextView 简单使用

  • 效果图
    在这里插入图片描述

  • 布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--做动画的布局-->
    <LinearLayout
        android:id="@+id/targetView"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="#ff00ff"
        android:orientation="vertical"
        android:gravity="center"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:textSize="20sp"
            android:text="我是内容区域 我是内容区域
                  我是内容区域 我是内容区域
                   我是内容区域
                   我是内容区域
                  我是内容区域我是内容区域" />
    </LinearLayout>

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="开始动画"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
  • 实现代码
public class Main11Activity extends AppCompatActivity {
    LinearLayout targetView ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        Fade fade = new Fade();
        getWindow().setEnterTransition(fade);
        getWindow().setExitTransition(fade);
        getWindow().setReenterTransition(fade);
        getWindow().setReturnTransition(fade);

        ChangeBounds changeBounds = new ChangeBounds();
        changeBounds.setDuration(1000);
        ChangeClipBounds changeClipBounds = new ChangeClipBounds();
        changeClipBounds.setDuration(1000);
        ChangeImageTransform changeImageTransform = new ChangeImageTransform();
        changeImageTransform.setDuration(1000);
        ChangeTransform changeTransform = new ChangeTransform();
        changeTransform.setDuration(1000);
        getWindow().setSharedElementEnterTransition(changeBounds);
        getWindow().setSharedElementExitTransition(changeClipBounds);
        getWindow().setSharedElementReenterTransition(changeImageTransform);
        getWindow().setSharedElementReturnTransition(changeTransform);

        getWindow().setSharedElementsUseOverlay(true);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main11);

        targetView = findViewById(R.id.targetView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                final int width = targetView.getMeasuredWidth();
                final int height = targetView.getMeasuredHeight();
                final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径
                Animator animator;
                if (targetView.getVisibility() == View.VISIBLE){
                    animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 0);
                    animator.setDuration(1000);
                    animator.setInterpolator(new AccelerateDecelerateInterpolator());
                    animator.start();
                    animator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            targetView.setVisibility(View.GONE);
                        }
                    });
                }else{
                    animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, 0, radius);
                    animator.setDuration(1000);
                    animator.setInterpolator(new AccelerateDecelerateInterpolator());
                    targetView.setVisibility(View.VISIBLE);
                    animator.start();
                    animator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            targetView.setVisibility(View.VISIBLE);
                        }
                    });
                }

            }
        });
    }
}

2. ImageView 简单使用

  • 效果图
    在这里插入图片描述

  • 布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--做动画的布局-->
    <LinearLayout
        android:id="@+id/targetView"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:orientation="vertical"
        android:gravity="center"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

            <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitCenter"
            android:src="@drawable/image_home_game_nor"/>
    </LinearLayout>

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="开始动画"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>

注意:
可以看到代码中在动画开始之前设置了targetView可见( targetView.setVisibility(View.VISIBLE);
animator.start();)因为前面我们介绍了揭露动画特性
重要特性:

  • 揭露动画是一个异步动画,它的回调方法都不能保证在准确的时间里调用,但误差不会很大。
  • 揭露对象要先于动画开始前显示(View.VISIBLE),因为动画开始时如果被操作对象处于隐藏状态,那么动画就不会有效果,所以就算是不可见的对象,开始动画前也需要设置为可见。

所以可以在监听动画动画开始回调时调用targetView.setVisibility(View.VISIBLE),但因为揭露动画是异步的,会有极小的概率导致view不可见,所以再动画开始之前最保险。

3. 结合属性动画,共享元素和揭露动画的简单实例

  • 效果图
    在这里插入图片描述

  • 布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AActivity">

<ImageView
    android:id="@+id/floatactionbtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/image_home_game_nor2"
    android:scaleType="centerCrop"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    android:transitionName="shareelement"/>

    <FrameLayout
        android:id="@+id/framelayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"
        android:background="@color/colorPrimary">

    </FrameLayout>

</android.support.constraint.ConstraintLayout>


---------------------------------分割线---------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/targetView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter"
        android:src="@drawable/image_home_game_nor"
        android:transitionName="shareelement" />
    <!--做动画的布局-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:orientation="vertical"
        android:gravity="center"
        android:visibility="gone"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

            <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="fitCenter"
            android:src="@drawable/image_home_game_nor"/>
    </LinearLayout>

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:text="开始动画"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>
  • 实现代码
    ActivityA 代码
public class ActivityA extends AppCompatActivity {

    private ImageView fab;
    private ConstraintLayout mCons;
    private FrameLayout mFram;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main10);
        fab = findViewById(R.id.floatactionbtn);
        mCons = findViewById(R.id.container);
        mFram = findViewById(R.id.framelayout);
        mFram.setVisibility(View.GONE);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Path path = new Path();
                path.moveTo(mCons.getMeasuredWidth()-fab.getWidth(),mCons.getMeasuredHeight() - fab.getHeight());
                path.quadTo(mCons.getMeasuredWidth()-300,mCons.getMeasuredHeight() -200,mCons.getMeasuredWidth()/2- fab.getWidth(),mCons.getMeasuredHeight()/2 - fab.getHeight()/2);
                ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(fab, "X", "Y", path);
                objectAnimator.setDuration(3000);
                objectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

                Path path2 = new Path();
                path2.moveTo(1.0f,1.0f);
                path2.lineTo(2.0f,2.0f);
                path2.lineTo(1.0f,1.0f);
                path2.lineTo(2.0f,2.0f);
                path2.lineTo(1.0f,1.0f);
                ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(fab, View.SCALE_X,View.SCALE_Y, path2);
                objectAnimator2.setDuration(4000);
                objectAnimator2.setInterpolator(new AccelerateDecelerateInterpolator());
                objectAnimator2.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        super.onAnimationEnd(animation);
                        Intent intent = new Intent(ActivityA.this, ActivityB.class);
                        ActivityOptionsCompat activityOptionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(ActivityA.this,fab,"shareelement");
                        startActivity(intent,activityOptionsCompat.toBundle());
                    }

                    @Override
                    public void onAnimationStart(Animator animation) {
                        super.onAnimationStart(animation);
                    }
                });

                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.playSequentially(objectAnimator,objectAnimator2);
                animatorSet.start();
            }
        });
    }
}

ActivityB 代码

public class ActivityB extends AppCompatActivity {
    View targetView ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main11);

        targetView = findViewById(R.id.targetView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        findViewById(R.id.start).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Animator animator;
                final int width = targetView.getMeasuredWidth();
                final int height = targetView.getMeasuredHeight();
                final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径
                if (targetView.getVisibility() == View.VISIBLE){
                    animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 0);
                    animator.setDuration(1000);
                    animator.setInterpolator(new AccelerateDecelerateInterpolator());
                    animator.start();
                    animator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            targetView.setVisibility(View.GONE);
                        }
                    });
                }else{
                    animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, 0, radius);
                    animator.setDuration(1000);
                    animator.setInterpolator(new AccelerateDecelerateInterpolator());
                    targetView.setVisibility(View.VISIBLE);
                    animator.start();
                    animator.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            targetView.setVisibility(View.VISIBLE);
                        }
                    });
                }

            }
        });

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                final int width = targetView.getMeasuredWidth();
                final int height = targetView.getMeasuredHeight();
                final float radius = (float)Math.sqrt(width*width + height*height) / 2;//半径
                Animator animator;
                animator = ViewAnimationUtils.createCircularReveal(targetView, width/2, height/2, radius, 20);
                animator.setDuration(3000);
                animator.setInterpolator(new AccelerateDecelerateInterpolator());
                targetView.setVisibility(View.VISIBLE);
                animator.start();
                animator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        targetView.setVisibility(View.GONE);
                    }
                });
            }
        },1000);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin-Dev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值