Android CircularReveal揭露动画三种实现

来源:互联网 发布:个人征信所用数据 编辑:程序博客网 时间:2024/05/20 20:05

1.概述
上一篇原本是准备介绍下揭露动画的,但是无奈没有5.0设备,于是乎装genymotion下载了半天。
genymotion配置
今天来介绍下揭露动画,首先看下效果。
这2个使用系统ViewAnimationUtils.createCircularReveal实现的:
这里写图片描述
这里写图片描述

接下来2个使用属性动画以及自定义圆形控件+属性动画实现:
这里写图片描述
这里写图片描述

以上通过FloatingActionButton点击变化的是单个View的效果,通过三个美女圆形ImageView点击是activity的跳转(应用设置了透明主题)。
还不知道圆形头像怎么制作的可以看:
http://blog.csdn.net/ch867179244/article/details/53522679

2.思路
揭露动画个人理解有点像layer,类似于一个东西上面铺了一层,显示时让上面那层有个揭开的效果去显示。
按照这个思路怎么实现了?
2.1 我们先设置需要View不可见,
2.2 在我们需要显示的时候,让View可见并且执行动画效果,
2.3 动画结束后,隐藏动画的View ,然后显示我们需要View(当然这个时候需要显示的view也可以给个出场动画)

注意点:
如果想让View刚加载出来就有揭露动画效果(比如activity切换时),这个时候需要注意2点。
1. 给View添加preDraw监听,在onPreDraw的回调中去执行动画,并且记住remove监听,这么做的原因是,如果直接在oncreate中给View添加动画,这个时候view可能还没完全加载。清除监听是为了防止多次调用。
2. 如果是activity时,需要覆盖系统默认的界面跳转动画效果。 overridePendingTransition
3. 使用属性动画,别忘记提供set(必须设置) ; get方法(属性动画没设置初始值时需要get)

3.代码实现
MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {  FloatingActionButton fab;  CirclePic ivCenter; //中间大图片  CirclePic cpLeft, cpCenter, cpRight; // 左中右依次是:系统默认 ;属性动画 ; 属性动画+自定义控件  ViewTreeObserver.OnPreDrawListener listener;  int centerX, centerY;  float startRadiu, endRadiu;  private static final int ANIMA_DURATION = 1 * 1000; //默认动画时间  @Override protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    initView();  }  private void initView() {    fab = (FloatingActionButton) findViewById(R.id.fab);    fab.setOnClickListener(this);    ivCenter = (CirclePic) findViewById(R.id.iv);    listener = new ViewTreeObserver.OnPreDrawListener() {      @Override public boolean onPreDraw() {        //这里一定要remove 避免执行多次        ivCenter.getViewTreeObserver().removeOnPreDrawListener(listener);        centerX = (ivCenter.getLeft() + ivCenter.getRight()) / 2;        //开始裁剪的中心点Y坐标        centerY = (ivCenter.getTop() + ivCenter.getBottom()) / 2;        //结束半径对角线        endRadiu = (float) Math.hypot(centerX, centerY);        //开始半径        startRadiu = 0;        anim(centerX, centerY, endRadiu, 0, ivCenter,            ivCenter.getVisibility() == View.INVISIBLE ? true : false);        return false;      }    };    ivCenter.getViewTreeObserver().addOnPreDrawListener(listener);    cpCenter = (CirclePic) findViewById(R.id.circlePic);    cpCenter.setOnClickListener(this);    cpLeft = (CirclePic) findViewById(R.id.circlePicLeft);    cpLeft.setOnClickListener(this);    cpRight = (CirclePic) findViewById(R.id.circlePicRight);    cpRight.setOnClickListener(this);  }  /**   * @param isShow 动画结束是否显示View   */  private void anim(int centerX, int centerY, float endRadiu, float startRadiu, final ImageView iv,      final boolean isShow) {    // fab的动画    //fab.setPivotY((iv.getHeight() + iv.getBottom()) / 2);    //final Animation rotationAnima = new RotateAnimation(isShow ? 0 : 360, isShow ? 360 : 0);    //fab.setAnimation(rotationAnima);    //rotationAnima.setDuration(ANIMA_DURATION);    //rotationAnima.setInterpolator(new AccelerateDecelerateInterpolator());    //rotationAnima.start();    //rotationAnima.setAnimationListener(new Animation.AnimationListener() {    //  @Override public void onAnimationStart(Animation animation) {    //    //  }    //    //  @Override public void onAnimationEnd(Animation animation) {    //    rotationAnima.cancel();    //    rotationAnima.setAnimationListener(null);    //  }    //    //  @Override public void onAnimationRepeat(Animation animation) {    //    //  }    //});    //ivCenter的动画    final Animator animator = ViewAnimationUtils.createCircularReveal(iv, centerX, centerY,        isShow ? startRadiu : endRadiu, isShow ? endRadiu : startRadiu);    animator.setInterpolator(new AccelerateDecelerateInterpolator());    animator.setDuration(ANIMA_DURATION);    animator.setStartDelay(0);    iv.setVisibility(View.VISIBLE);    animator.start();    animator.addListener(new AnimatorListenerAdapter() {      @Override public void onAnimationEnd(Animator animation) {        if (!isShow) {          iv.setVisibility(View.INVISIBLE);        }      }    });  }  @Override public void onClick(View view) {    switch (view.getId()) {      case R.id.fab:        anim(centerX, centerY, endRadiu, startRadiu, ivCenter,            ivCenter.getVisibility() == View.INVISIBLE ? true : false);        break;      case R.id.circlePic:        toSecondActivity(Constant.CENTER);        break;      case R.id.circlePicLeft:        toSecondActivity(Constant.LEFT);        break;      case R.id.circlePicRight:        toSecondActivity(Constant.RIGHT);        break;    }  }  /**   * 跳转secondActivity   */  private void toSecondActivity(int whichAnima) {    Intent intent = new Intent(MainActivity.this, SecondActivity.class);    intent.putExtra("param", whichAnima);    startActivity(intent);    //取消默认的activity切换动画    overridePendingTransition(0, 0);  }}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    >  <demos.ch.com.animationdemo.CirclePic      android:id="@+id/iv"      android:layout_width="@dimen/circle_radiu_big"      android:layout_height="@dimen/circle_radiu_big"      app:radiu="@dimen/circle_radiu_big"      android:layout_centerInParent="true"      android:src="@mipmap/d"      android:visibility="invisible"      />  <android.support.design.widget.FloatingActionButton      android:id="@+id/fab"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:layout_below="@+id/iv"      android:layout_centerHorizontal="true"      android:src="@mipmap/ic_launcher"      />  <demos.ch.com.animationdemo.CirclePic      android:layout_width="@dimen/circle_radiu"      android:layout_height="@dimen/circle_radiu"      app:radiu="@dimen/circle_radiu"      android:src="@mipmap/f"      android:id="@+id/circlePic"      android:layout_alignParentTop="true"      android:layout_centerHorizontal="true"      />  <demos.ch.com.animationdemo.CirclePic      android:layout_width="@dimen/circle_radiu"      android:layout_height="@dimen/circle_radiu"      app:radiu="@dimen/circle_radiu"      android:src="@mipmap/e"      android:id="@+id/circlePicRight"      android:layout_alignParentRight="true"      />  <demos.ch.com.animationdemo.CirclePic      android:layout_width="@dimen/circle_radiu"      android:layout_height="@dimen/circle_radiu"      app:radiu="@dimen/circle_radiu"      android:src="@mipmap/g"      android:id="@+id/circlePicLeft"      android:layout_alignParentLeft="true"      /></RelativeLayout>

SecondActivity.java

public class SecondActivity extends AppCompatActivity implements View.OnClickListener {  Button button;  TextView tv;  CircleBackGround cgb;  ViewTreeObserver.OnPreDrawListener listener;  int width, height;  int whichAnima;  private static final int ANIMA_DURATION = 1 * 1000; //默认动画时间  @Override public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_second);    DisplayMetrics dm = new DisplayMetrics();    getWindowManager().getDefaultDisplay().getMetrics(dm);    width = dm.widthPixels;    height = dm.heightPixels;    if (null != getIntent()) {      whichAnima = getIntent().getIntExtra("param", Constant.CENTER);    }    initView();  }  private void initView() {    button = (Button) findViewById(R.id.btn);    button.setOnClickListener(this);    tv = (TextView) findViewById(R.id.tv);    cgb = (CircleBackGround) findViewById(R.id.cbg);    cgb.setCx(width / 2);    cgb.setCy(height / 2);    listener = new ViewTreeObserver.OnPreDrawListener() {      @Override public boolean onPreDraw() {        //这里一定要remove 避免执行多次        startWhichAnima();        return false;      }    };    if (whichAnima == Constant.RIGHT) {      cgb.getViewTreeObserver().addOnPreDrawListener(listener);    } else {      tv.getViewTreeObserver().addOnPreDrawListener(listener);    }  }  /**   * 启动动画   */  private void startWhichAnima() {    switch (whichAnima) {      case Constant.CENTER:        //2.属性动画实现        tv.getViewTreeObserver().removeOnPreDrawListener(listener);        tv.setVisibility(View.VISIBLE);        propertyAnima();        break;      case Constant.LEFT:        //1.系统揭露动画实现        tv.getViewTreeObserver().removeOnPreDrawListener(listener);        tv.setVisibility(View.VISIBLE);        circularAnima();        break;      case Constant.RIGHT:        //3.自定义控件+属性动画实现        cgb.getViewTreeObserver().removeOnPreDrawListener(listener);        cgb.setVisibility(View.VISIBLE);        CirclePropertyAnima();        break;    }  }  /**   * 自定义控件+属性动画 圆形   */  private void CirclePropertyAnima() {    //代实现    ObjectAnimator animaRadiu =        ObjectAnimator.ofFloat(cgb, "radiu", 0.0f, (float) Math.hypot(width / 2, height / 2));    animaRadiu.setDuration(ANIMA_DURATION);    animaRadiu.setInterpolator(new AccelerateDecelerateInterpolator());    animaRadiu.addListener(new AnimatorListenerAdapter() {      @Override public void onAnimationEnd(Animator animation) {        animaEndAction();      }    });    animaRadiu.start();  }  /**   * 使用属性动画实现揭露 效果不是圆形的   */  public void propertyAnima() {    final AnimatorSet animaSet = new AnimatorSet();    ObjectAnimator animaX = ObjectAnimator.ofFloat(tv, "x", width, 0);    ObjectAnimator animaY = ObjectAnimator.ofFloat(tv, "y", height, 0);    //ObjectAnimator animaAlpha = ObjectAnimator.ofFloat(tv,"alpha",1.0f,0.0f);    animaSet.setDuration(ANIMA_DURATION);    animaSet.setInterpolator(new AccelerateDecelerateInterpolator());    animaSet.playTogether(animaX, animaY/*,animaAlpha*/);    animaSet.addListener(new AnimatorListenerAdapter() {      @Override public void onAnimationEnd(Animator animation) {        animaEndAction();      }    });    animaSet.setStartDelay(0);    animaSet.start();  }  /**   * 使用createCircularReveal实现揭露效果   */  private void circularAnima() {    int centerX = (tv.getLeft() + tv.getRight()) / 2;    //开始裁剪的中心点Y坐标    int centerY = (tv.getTop() + tv.getBottom()) / 2;    //开始半径    float startRadiu = (float) Math.hypot(centerX, centerY);    //结束半径对角线    float endRadiu = (float) Math.min(tv.getWidth(), tv.getHeight()) / 2;    final Animator animator =        ViewAnimationUtils.createCircularReveal(tv, centerX, centerY, startRadiu, 0);    animator.setInterpolator(new AccelerateDecelerateInterpolator());    animator.setDuration(ANIMA_DURATION);    animator.setStartDelay(0);    animator.start();    animator.addListener(new AnimatorListenerAdapter() {      @Override public void onAnimationEnd(Animator animation) {        animaEndAction();      }    });  }  /**   * 动画结束后续动作   */  private void animaEndAction() {    tv.setVisibility(View.INVISIBLE);    cgb.setVisibility(View.INVISIBLE);    button.setVisibility(View.VISIBLE);    //ObjectAnimator anima = ObjectAnimator.ofFloat(button,"alpha",0.0f,1.0f);    //ObjectAnimator anima1 = ObjectAnimator.ofFloat(button,"rotation",0,360);    //anima1.setDuration(ANIMA_DURATION);    //anima1.setInterpolator(new AccelerateDecelerateInterpolator());    //anima1.start();  }  @Override public void onClick(View view) {    if (view.getId() == R.id.btn) {      onBackPressed();    }  }}

sceond_activity.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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"    >  <TextView      android:id="@+id/tv"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:visibility="invisible"      android:background="@color/colorAccent"      />  <demos.ch.com.animationdemo.CircleBackGround      android:id="@+id/cbg"      android:layout_width="match_parent"      android:layout_height="match_parent"      app:radiuCbg="@dimen/circle_radiu_big"      app:pColor="#FFE7CE0F"      android:visibility="invisible"      />  <Button      android:id="@+id/btn"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:layout_centerInParent="true"      android:background="#c8ccef"      android:textColor="#FFB5AB15"      android:textSize="24dp"      android:text="onBackPressed"      android:visibility="invisible"      /></RelativeLayout>

里面有2个自定义控件,一个CircleImageView这个就是上篇博客中copy过来,代码就不贴了,CircleBackGround很简单,就是自定义ImageView画实心圆。
CircleBackGround.java

public class CircleBackGround extends ImageView {  private float radiu = 0; //背景圆半径 用于属性动画提供set get方法  private int color = Color.RED; //画笔颜色  private float cx, cy;  public float getCx() {    return cx;  }  public void setCx(float cx) {    this.cx = cx;  }  public float getCy() {    return cy;  }  public void setCy(float cy) {    this.cy = cy;  }  public float getRadiu() {    return radiu;  }  public void setRadiu(float radiu) {    this.radiu = radiu;    invalidate();  }  public CircleBackGround(Context context) {    this(context, null);  }  public CircleBackGround(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public CircleBackGround(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    init(attrs);  }  private void init(AttributeSet attrs) {    TypedArray a = getResources().obtainAttributes(attrs, R.styleable.CircleBackGround);    radiu = (int) a.getDimension(R.styleable.CircleBackGround_radiuCbg, 0);    color =  a.getColor(R.styleable.CircleBackGround_pColor,0xffffff);    a.recycle();  }  @Override protected void onDraw(Canvas canvas) {    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);    paint.setStyle(Paint.Style.FILL_AND_STROKE);    paint.setTypeface(Typeface.DEFAULT_BOLD);    paint.setColor(color);    canvas.drawCircle(getCx(), getCy(), radiu, paint);  }}

当然揭露动画结束之后可以给需要显示的View设置些出场动画,类似于Activity切换有个enter_anim 和out_anim,以上就是实现代码,比较简单所以就不一一讲解了。按照上述的思路和注意点来实现就行了。大家有什么别的好的ideal也可以留言一起学习。
完整代码地址:
https://github.com/ChenHaoLw/AnimationDemo

0 0
原创粉丝点击