android 实现圆形波纹动画

在app中这种效果用的越来越多了,下面看看如何实现这种效果,这里我整理了两种实现这种效果的方式

方式一:
使用github上面的类库,把这个类库加入到我们的项目中即可
https://github.com/ozodrukh/CircularReveal
具体代码实现
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <io.codetail.widget.RevealLinearLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context="com.leyue100.fenjie.MainActivity">
 8 
 9     <LinearLayout
10         android:id="@+id/ly"
11         android:layout_width="match_parent"
12         android:layout_height="match_parent"
13         android:background="@color/my_blue"
14         android:gravity="center"
15         android:orientation="vertical">
16         <ImageView
17             android:id="@+id/image"
18             android:layout_width="wrap_content"
19             android:layout_height="wrap_content"
20             android:layout_gravity="center"
21             android:src="@mipmap/ic_launcher"
22 
23             />
24 
25     </LinearLayout>
26 </io.codetail.widget.RevealLinearLayout>

Activity设置动画

 1 package com.leyue100.fenjie;
 2 
 3 import android.os.Bundle;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.view.animation.AccelerateDecelerateInterpolator;
 6 import android.widget.ImageView;
 7 import android.widget.LinearLayout;
 8 
 9 import com.leyue100.fenjie.util.Util;
10 
11 import butterknife.Bind;
12 import butterknife.ButterKnife;
13 import io.codetail.animation.SupportAnimator;
14 import io.codetail.animation.ViewAnimationUtils;
15 
16 public class MainActivity extends AppCompatActivity {
17 
18 
19     @Bind(R.id.image)
20     ImageView image;
21     @Bind(R.id.ly)
22     LinearLayout ly;
23 
24     private boolean hasAnimationStarted;
25 
26     @Override
27     protected void onCreate(Bundle savedInstanceState) {
28         super.onCreate(savedInstanceState);
29         setContentView(R.layout.activity_main);
30         ButterKnife.bind(this);
31     }
32 
33     @Override
34     public void onWindowFocusChanged(boolean hasFocus) {
35         //控制动画显示一次
36         if (hasFocus && !hasAnimationStarted) {
37             startCircular();
38         }
39     }
40 
41     private void startCircular() {
42         //获取图片所在屏幕的位置
43         int[] location = new int[2];
44         image.getLocationOnScreen(location);
45         
46         //设置圆的中心点
47         int cx = location[0] + image.getWidth()/2;
48         int cy = location[1] - image.getHeight()/2 - Util.dpToPx(24);
49 
50         int dx = Math.max(cx, ly.getWidth() - cx);
51         int dy = Math.max(cy, ly.getHeight() - cy);
52         //设置半径
53         float finalRadius = (float) Math.hypot(dx, dy);
54         SupportAnimator animator = ViewAnimationUtils.createCircularReveal(ly, cx, cy, 0, finalRadius);
55         animator.setInterpolator(new AccelerateDecelerateInterpolator());
56         animator.setDuration(3000);
57         animator.start();
58         hasAnimationStarted = true;
59     }
60 }

使用第三方类很简单就可以实现出来

下面介绍一种自己实现的方式

自定义view 

RevealBackgroundView

  1 package com.leyue100.lingwai.view;
  2 
  3 import android.animation.Animator;
  4 import android.animation.AnimatorListenerAdapter;
  5 import android.animation.ObjectAnimator;
  6 import android.content.Context;
  7 import android.graphics.Canvas;
  8 import android.graphics.Color;
  9 import android.graphics.Paint;
 10 import android.util.AttributeSet;
 11 import android.view.View;
 12 import android.view.animation.AccelerateDecelerateInterpolator;
 13 import android.view.animation.Interpolator;
 14 
 15 /**
 16  * Created by lihao on 16/2/18.
 17  * Version : 1.0
 18  * desc:
 19  */
 20 public class RevealBackgroundView extends View {
 21 
 22     //设置状态
 23     public static final int STATE_NOT_STARTED = 0;
 24     public static final int STATE_FILL_STARTED = 1;
 25     public static final int STATE_FINSHED = 3;
 26 
 27     private static final Interpolator INTERPOLATOR = new AccelerateDecelerateInterpolator();
 28     private static final int FILL_TIME = 4000;
 29 
 30     private int state = STATE_NOT_STARTED;
 31 
 32     private Paint fillPaint;
 33     private int currentRadius;
 34     private ObjectAnimator revealAnimator;
 35 
 36     private int startLocationX;
 37     private int startLocationY;
 38 
 39     private OnStateChangeListener onStateChangeListener;
 40 
 41 
 42     public RevealBackgroundView(Context context) {
 43         super(context);
 44         init();
 45     }
 46 
 47     public RevealBackgroundView(Context context, AttributeSet attrs) {
 48         super(context, attrs);
 49         init();
 50     }
 51 
 52     public RevealBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
 53         super(context, attrs, defStyleAttr);
 54         init();
 55     }
 56 
 57     /**
 58      * 初始化数据
 59      */
 60     private void init() {
 61         fillPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG);
 62         fillPaint.setStyle(Paint.Style.FILL);
 63         fillPaint.setColor(Color.WHITE);
 64     }
 65 
 66     public void setFillPaintColor(int color) {
 67         fillPaint.setColor(color);
 68     }
 69 
 70     public void startFromLocation(int[] tapLocationOnScreen) {
 71         //设置状态为开始
 72         changeState(STATE_FILL_STARTED);
 73         //获取到中心点即动画开始的位置
 74         startLocationX = tapLocationOnScreen[0];
 75         startLocationY = tapLocationOnScreen[1];
 76         //设置半径
 77         int finalRadius = (int) Math.hypot(getHeight(), getWidth());
 78         //设置动画 重点currentRadius设置动画的半径
 79         revealAnimator = ObjectAnimator.ofInt(this, "currentRadius", 0, finalRadius);
 80         revealAnimator.setInterpolator(INTERPOLATOR);
 81         revealAnimator.setDuration(FILL_TIME);
 82         revealAnimator.addListener(new AnimatorListenerAdapter() {
 83             @Override
 84             public void onAnimationEnd(Animator animation) {
 85                 super.onAnimationEnd(animation);
 86                 changeState(STATE_FINSHED);
 87             }
 88         });
 89         revealAnimator.start();
 90     }
 91 
 92     public void setToFinishedFrame() {
 93         changeState(STATE_FINSHED);
 94         invalidate();
 95     }
 96 
 97     @Override
 98     protected void onDraw(Canvas canvas) {
 99         if (state == STATE_FINSHED){
100             //状态完成画一个矩形
101             canvas.drawRect(0,0,getWidth(),getHeight(),fillPaint);
102         } else {
103             //画圆
104             canvas.drawCircle(startLocationX,startLocationY,currentRadius,fillPaint);
105         }
106     }
107 
108     /**
109      * 设置状态
110      * @param state
111      */
112     private void changeState(int state) {
113         if(this.state == state) {
114             return;
115         }
116         this.state = state;
117         if(onStateChangeListener != null) {
118             onStateChangeListener.onStateChange(state);
119         }
120     }
121 
122     /**
123      * 动画回调此方法
124      * @param radius
125      */
126     public void setCurrentRadius(int radius) {
127         this.currentRadius = radius;
128         invalidate();
129     }
130 
131     public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
132         this.onStateChangeListener = onStateChangeListener;
133     }
134     public interface OnStateChangeListener{
135         void onStateChange(int state);
136     }
137 }

使用自定义控件:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     tools:context="com.leyue100.lingwai.MainActivity">
 7 
 8     <com.leyue100.lingwai.view.RevealBackgroundView
 9         android:id="@+id/backgroundView"
10         android:layout_width="match_parent"
11         android:layout_height="match_parent" />
12     <ImageView
13         android:id="@+id/image"
14         android:layout_width="wrap_content"
15         android:layout_height="wrap_content"
16         android:layout_gravity="center"
17         android:src="@mipmap/ic_launcher"
18         android:layout_centerInParent="true"
19         />
20 </RelativeLayout>

Activity中使用

package com.leyue100.lingwai;

import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.Toast;

import com.leyue100.lingwai.view.RevealBackgroundView;

import butterknife.Bind;
import butterknife.ButterKnife;

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.backgroundView)
    RevealBackgroundView backgroundView;
    @Bind(R.id.image)
    ImageView image;

    private final static String TAG = "MainActivity";
    private boolean hasAnimationStarted;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        if (hasFocus && !hasAnimationStarted) {
            setupRevaalBackground();
        }

    }

    public void setupRevaalBackground() {
        backgroundView.setOnStateChangeListener(new RevealBackgroundView.OnStateChangeListener() {
            @Override
            public void onStateChange(int state) {
                if (state == RevealBackgroundView.STATE_FINSHED) {
                    Toast.makeText(MainActivity.this, "动画结束", Toast.LENGTH_SHORT).show();
                }
            }
        });
        
        //获取动画开始位置
        final int[] location = new int[2];
        image.getLocationOnScreen(location);
        
        //启动动画
        backgroundView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                backgroundView.getViewTreeObserver().removeOnPreDrawListener(this);
                backgroundView.setFillPaintColor(Color.parseColor("#2196F3"));
                backgroundView.startFromLocation(location);
                hasAnimationStarted = true;
                return true;

            }
        });

    }
}

这两种方式做起来都很简单

原文地址:https://www.cnblogs.com/lihaolihao/p/5200883.html