17 | * Created by wangchenlong on 16/2/26. 18 | */ 19 | public class GuiUtils { 20 | public interface OnRevealAnimationListener { 21 | void onRevealHide(); 22 | 23 | void onRevealShow(); 24 | } 25 | 26 | // 圆圈爆炸效果显示 27 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 28 | public static void animateRevealShow( 29 | final Context context, final View view, 30 | final int startRadius, @ColorRes int color, 31 | OnRevealAnimationListener listener) { 32 | int cx = (view.getLeft() + view.getRight()) / 2; 33 | int cy = (view.getTop() + view.getBottom()) / 2; 34 | 35 | float finalRadius = (float) Math.hypot(view.getWidth(), view.getHeight()); 36 | 37 | // 设置圆形显示动画 38 | Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, startRadius, finalRadius); 39 | anim.setDuration(300); 40 | anim.setInterpolator(new AccelerateDecelerateInterpolator()); 41 | anim.addListener(new AnimatorListenerAdapter() { 42 | @Override public void onAnimationEnd(Animator animation) { 43 | super.onAnimationEnd(animation); 44 | view.setVisibility(View.VISIBLE); 45 | listener.onRevealShow(); 46 | } 47 | 48 | @Override public void onAnimationStart(Animator animation) { 49 | super.onAnimationStart(animation); 50 | view.setBackgroundColor(ContextCompat.getColor(context, color)); 51 | } 52 | }); 53 | 54 | anim.start(); 55 | } 56 | 57 | // 圆圈凝聚效果 58 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 59 | public static void animateRevealHide( 60 | final Context context, final View view, 61 | final int finalRadius, @ColorRes int color, 62 | OnRevealAnimationListener listener 63 | ) { 64 | int cx = (view.getLeft() + view.getRight()) / 2; 65 | int cy = (view.getTop() + view.getBottom()) / 2; 66 | int initialRadius = view.getWidth(); 67 | // 与入场动画的区别就是圆圈起始和终止的半径相反 68 | Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, finalRadius); 69 | anim.setDuration(300); 70 | anim.setInterpolator(new AccelerateDecelerateInterpolator()); 71 | anim.addListener(new AnimatorListenerAdapter() { 72 | @Override public void onAnimationStart(Animator animation) { 73 | super.onAnimationStart(animation); 74 | view.setBackgroundColor(ContextCompat.getColor(context, color)); 75 | } 76 | 77 | @Override public void onAnimationEnd(Animator animation) { 78 | super.onAnimationEnd(animation); 79 | listener.onRevealHide(); 80 | view.setVisibility(View.INVISIBLE); 81 | } 82 | }); 83 | anim.start(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_circle_reveal_demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_circle_reveal_demo; 2 | 3 | import android.app.ActivityOptions; 4 | import android.content.Intent; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.design.widget.FloatingActionButton; 8 | import android.support.design.widget.Snackbar; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | 15 | import butterknife.Bind; 16 | import butterknife.ButterKnife; 17 | 18 | public class MainActivity extends AppCompatActivity { 19 | 20 | @Bind(R.id.fab) FloatingActionButton mFab; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | ButterKnife.bind(this); 27 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 28 | setSupportActionBar(toolbar); 29 | } 30 | 31 | @Override 32 | public boolean onCreateOptionsMenu(Menu menu) { 33 | // Inflate the menu; this adds items to the action bar if it is present. 34 | getMenuInflater().inflate(R.menu.menu_main, menu); 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean onOptionsItemSelected(MenuItem item) { 40 | // Handle action bar item clicks here. The action bar will 41 | // automatically handle clicks on the Home/Up button, so long 42 | // as you specify a parent activity in AndroidManifest.xml. 43 | int id = item.getItemId(); 44 | 45 | //noinspection SimplifiableIfStatement 46 | if (id == R.id.action_settings) { 47 | return true; 48 | } 49 | 50 | return super.onOptionsItemSelected(item); 51 | } 52 | 53 | // Fab的跳转事件 54 | public void startOtherActivity(View view) { 55 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 56 | ActivityOptions options = 57 | ActivityOptions.makeSceneTransitionAnimation(this, mFab, mFab.getTransitionName()); 58 | startActivity(new Intent(this, OtherActivity.class), options.toBundle()); 59 | } else { 60 | startActivity(new Intent(this, OtherActivity.class)); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/me/chunyu/spike/wcl_circle_reveal_demo/OtherActivity.java: -------------------------------------------------------------------------------- 1 | package me.chunyu.spike.wcl_circle_reveal_demo; 2 | 3 | import android.annotation.TargetApi; 4 | import android.os.Build; 5 | import android.os.Bundle; 6 | import android.os.Handler; 7 | import android.os.Looper; 8 | import android.support.annotation.Nullable; 9 | import android.support.design.widget.FloatingActionButton; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.transition.Fade; 12 | import android.transition.Transition; 13 | import android.transition.TransitionInflater; 14 | import android.view.View; 15 | import android.view.animation.Animation; 16 | import android.view.animation.AnimationUtils; 17 | import android.widget.ImageView; 18 | import android.widget.RelativeLayout; 19 | import android.widget.TextView; 20 | 21 | import butterknife.Bind; 22 | import butterknife.ButterKnife; 23 | 24 | /** 25 | * 跳转的Activity 26 | *
27 | * Created by wangchenlong on 16/2/26.
28 | */
29 | public class OtherActivity extends AppCompatActivity {
30 |
31 | @Bind(R.id.other_fab_circle) FloatingActionButton mFabCircle;
32 | @Bind(R.id.other_tv_container) TextView mTvContainer;
33 | @Bind(R.id.other_iv_close) ImageView mIvClose;
34 | @Bind(R.id.other_rl_container) RelativeLayout mRlContainer;
35 |
36 | @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | setContentView(R.layout.activity_other);
39 | ButterKnife.bind(this);
40 |
41 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
42 | setupEnterAnimation(); // 入场动画
43 | setupExitAnimation(); // 退场动画
44 | } else {
45 | initViews();
46 | }
47 | }
48 |
49 | // 入场动画
50 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
51 | private void setupEnterAnimation() {
52 | Transition transition = TransitionInflater.from(this)
53 | .inflateTransition(R.transition.arc_motion);
54 | transition.addListener(new Transition.TransitionListener() {
55 | @Override public void onTransitionStart(Transition transition) {
56 |
57 | }
58 |
59 | @Override public void onTransitionEnd(Transition transition) {
60 | transition.removeListener(this);
61 | animateRevealShow();
62 | }
63 |
64 | @Override public void onTransitionCancel(Transition transition) {
65 |
66 | }
67 |
68 | @Override public void onTransitionPause(Transition transition) {
69 |
70 | }
71 |
72 | @Override public void onTransitionResume(Transition transition) {
73 |
74 | }
75 | });
76 | getWindow().setSharedElementEnterTransition(transition);
77 | }
78 |
79 | // 动画展示
80 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
81 | private void animateRevealShow() {
82 | GuiUtils.animateRevealShow(
83 | this, mRlContainer,
84 | mFabCircle.getWidth() / 2, R.color.colorAccent,
85 | new GuiUtils.OnRevealAnimationListener() {
86 | @Override public void onRevealHide() {
87 |
88 | }
89 |
90 | @Override public void onRevealShow() {
91 | initViews();
92 | }
93 | });
94 | }
95 |
96 | // 退出动画
97 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
98 | private void setupExitAnimation() {
99 | Fade fade = new Fade();
100 | fade.setDuration(300);
101 | getWindow().setReturnTransition(fade);
102 | }
103 |
104 | // 初始化视图
105 | private void initViews() {
106 | new Handler(Looper.getMainLooper()).post(() -> {
107 | Animation animation = AnimationUtils.loadAnimation(this, android.R.anim.fade_in);
108 | animation.setDuration(300);
109 |
110 | mTvContainer.setVisibility(View.VISIBLE);
111 | mIvClose.setVisibility(View.VISIBLE);
112 | mTvContainer.startAnimation(animation);
113 | mIvClose.setAnimation(animation);
114 | });
115 | }
116 |
117 | // 退出按钮
118 | public void backActivity(View view) {
119 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
120 | onBackPressed();
121 | } else {
122 | defaultBackPressed();
123 | }
124 | }
125 |
126 | // 退出事件
127 | @Override public void onBackPressed() {
128 | GuiUtils.animateRevealHide(
129 | this, mRlContainer,
130 | mFabCircle.getWidth() / 2, R.color.colorAccent,
131 | new GuiUtils.OnRevealAnimationListener() {
132 | @Override
133 | public void onRevealHide() {
134 | defaultBackPressed();
135 | }
136 |
137 | @Override
138 | public void onRevealShow() {
139 |
140 | }
141 | });
142 | }
143 |
144 | // 默认回退
145 | private void defaultBackPressed() {
146 | super.onBackPressed();
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_close_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpikeKing/wcl-circle-reveal-demo/3ff38d62d3ce45bcd982809a97ca2cb552c88b84/app/src/main/res/drawable-nodpi/ic_close_white.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |