在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; } }); } }
这两种方式做起来都很简单