本文介绍了Android圆形揭露动画的使用。
概述
揭露动画是Android L中新引入的动画,裁剪View的边界的动画。当显示或隐藏一组UI元素时揭露动画可以给用户提供视觉连续性。这个动画经常用在悬浮按钮上。
配置
使用ViewAnimationUtils.createCircularReveal()方法可以创建揭露动画。
对于未显示的View使用下面的代码产生揭露动画:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19void enterReveal(){
// previously invisible view
final View myView = findViewById(R.id.my_view);
// get the center for the clipping circle
int cx = myView.getMeasuredWidth() / 2;
int cy = myView.getMeasuredHeight() / 2;
// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight()) / 2;
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();
}
隐藏已显示的View使用下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27void exitReveal(){
// previously visible view
final View myView = findViewById(R.id.my_view);
// get the center for the clipping circle
int cx = myView.getMeasuredWidth() / 2;
int cy = myView.getMeasuredHeight() / 2;
// get the initial radius for the clipping circle
int initialRadius = myView.getWidth() / 2;
// create the animation (the final radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);
// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation){
super.onAnimationEnd(animation);
myView.setVisibility(View.INVISIBLE);
}
});
// start the animation
anim.start();
}
View过渡
在Activity进入过渡完成之后调用enterReveal():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35private Transition.TransitionListener mEnterTransitionListener;
@Override
protected void onCreate(Bundle savedInstanceState){
...
mEnterTransitionListener = new Transition.TransitionListener() {
@Override
public void onTransitionStart(Transition transition){
}
@Override
public void onTransitionEnd(Transition transition){
enterReveal();
}
@Override
public void onTransitionCancel(Transition transition){
}
@Override
public void onTransitionPause(Transition transition){
}
@Override
public void onTransitionResume(Transition transition){
}
};
getWindow().getEnterTransition().addListener(mEnterTransitionListener);
}
修改enterReveal()方法当动画结束后移除监听。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35private void enterReveal(){
// previously invisible view
final View myView = findViewById(R.id.my_view);
// get the center for the clipping circle
int cx = myView.getMeasuredWidth() / 2;
int cy = myView.getMeasuredHeight() / 2;
// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight()) / 2;
Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
myView.setVisibility(View.VISIBLE);
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation){
}
@Override
public void onAnimationEnd(Animator animation){
getWindow().getEnterTransition().removeListener(mEnterTransitionListener);
}
@Override
public void onAnimationCancel(Animator animation){
}
@Override
public void onAnimationRepeat(Animator animation){
}
});
anim.start();
}
退出揭露动画完成之后销毁Activity:
1
2
3
4
5
6
7
8
9
10anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation){
super.onAnimationEnd(animation);
myView.setVisibility(View.INVISIBLE);
// Finish the activity after the exit transition completes.
supportFinishAfterTransition();
}
});
为了开启ActionBar的向上或返回按钮的退出揭露过渡,分别在onOptionsItemSelected()和onBackPressed()调用exitReveal()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15@Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()) {
// Respond to the action bar's Up/Home button
case android.R.id.home:
exitReveal();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed(){
exitReveal();
}
常见问题
如果你直接在View上使用揭露动画,它可能看起来有些奇怪,因此图形的一部分边也被揭露了。为了解决这个问题,你可以把View嵌入到用描边作为背景的FrameLayout中。通过这样处理,揭露动画的View和背景部分保持一致,因此它看起来只有颜色部分被揭露。
circular_button.xml:
1
2
3
4
5
6<?xml version="1.0" encoding="utf-8"?>
1
2
3
4
5
6
7
8
9
10
11
android:layout_width="@dimen/button_size"
android:layout_height="@dimen/button_size"
android:background="@drawable/circular_button">
android:id:@"+id/my_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
...
高级
为了当用户轻击View让揭露动画开始时看起来更自然,你可以从MotionEvent获取x和y的坐标,使用它开启揭露效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@Override
public boolean onTouch(View view, MotionEvent motionEvent){
if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight()) / 2;
// create the animator for this view (the start radius is zero)
Animator anim =
ViewAnimationUtils.createCircularReveal(myView, (int) motionEvent.getX(), (int) motionEvent.getY(), 0, finalRadius);
// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();
}
return false;
}
参考