引导动画

项目地址:Github

动画效果:

引导动画

实现原理分析

  1. 清单文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <manifest package="cn.lry.animation"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
    android:name=".guide.MainActivity"
    android:label="@string/app_name">
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    </activity>

    <activity android:name=".guide.GuideActivity"/>
    </application>

    </manifest>

    主要分为连个页面,一个是墨迹天气的引导页面,就是GIF中涨势的效果,另外一个也是差不多的动画效果的只不过是左右滑动的引导页面

  2. 主页面布局MainActivity,主页面主要有一个viewpager构成,滑动方式为vertical

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <cn.lry.animation.viewpager.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:orientation="vertical"/>

    </LinearLayout>
  3. ViewPager的初始化,通过xml文件来初始化每个页面的视图,然后通过pagers.add(view1)添加到ViewPager中,总共有四个

    1
    2
    3
    4
    5
    6
    7
    View view1 = LayoutInflater.from(this).inflate(R.layout.layout_tutorial_1, null);
    t1_icon1= (ImageView) view1.findViewById(R.id.t1_icon1);
    t1_icon2 = (ImageView) view1.findViewById(R.id.t1_icon2);
    t1_fixed = (ImageView) view1.findViewById(R.id.t1_fixed);
    t1_next = (ImageView) view1.findViewById(R.id.t1_next);
    pagers.add(view1);
    .........四个类似的页面
  4. 我们看其中一个页面的布局R.layout.layout_tutorial_1,也就是将页面上的几个图片分别用ImageView来进行布局分布。每个图片都是一个png的图片

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@android:color/white"
    android:gravity="center"
    android:orientation="vertical" >

    <ImageView
    android:id="@+id/t1_fixed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="15.0dip"
    android:src="@mipmap/tutorial1_fixed" />

    <RelativeLayout
    android:id="@+id/center_layout"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true" >

    <ImageView
    android:id="@+id/t1_icon1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="180.0dip"
    android:layout_marginTop="53.0dip"
    android:background="@drawable/t1_frame_animation" />

    <ImageView
    android:id="@+id/t1_icon2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/t1_icon1"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30.0dip"
    android:src="@mipmap/tutorial1_icon3"
    android:visibility="visible" />

    <ImageView
    android:id="@+id/t1_static"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:src="@mipmap/tutorial1_static"
    android:visibility="visible" />

    <ImageView
    android:id="@+id/t1_text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/t1_static"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="10.0dip"
    android:src="@mipmap/tutorial1_text"
    android:visibility="visible" />
    </RelativeLayout>

    <ImageView
    android:id="@+id/t1_next"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20.0dip"
    android:src="@mipmap/tutorial_next" />

    </LinearLayout>

  5. 动画的实现主要靠private void animal(int position) 方法,在页面切换的时候,去启动或者禁用视图控件的动画

每个部分的动画实现

第一页分析

  • 极低耗电 这几个字的放大缩小动画

    极低耗电为一个图片 t1_fixed = (ImageView) view1.findViewById(R.id.t1_fixed);

    1
    2
    3
    4
    5
    6
    <ImageView
    android:id="@+id/t1_fixed"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="15.0dip"
    android:src="@mipmap/tutorial1_fixed" />

    顶部动画加载

    1
    animationTop = AnimationUtils.loadAnimation(MainActivity.this, R.anim.tutorail_scalate_top);

    启动动画

    1
    t1_fixed.startAnimation(animationTop);

    主要分析这个动画的描述R.anim.tutorail_scalate_top,主要定义了两个动画效果scale,放大缩小,动画时长1000ms,x,y从1.0变为1.5倍大,重复模式reverse为倒序回复,如果设置为restart的话,表示从头回放,repeatcount负一表示无限循环;另外一个是alpha,时间也是1000,这样就是一边放大缩小,一边透明度渐变,透明度从1变为0.5

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
    android:duration="1000"
    android:fromXScale="1.0"
    android:fromYScale="1.0"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1.5"
    android:toYScale="1.5"
    android:repeatMode="reverse"
    android:repeatCount="-1"/>
    <alpha
    android:fromAlpha="1.0"
    android:toAlpha="0.5"
    android:duration="1000"
    android:repeatMode="reverse"
    android:repeatCount="-1"/>
    </set>

    <!-- 尺寸伸缩动画效果 scale
    属性:interpolator 指定一个动画的插入器
    常见动画插入器:
    accelerate_decelerate_interpolator 加速-减速 动画插入器
    accelerate_interpolator 加速-动画插入器
    decelerate_interpolator 减速- 动画插入器
    anticipate_interpolator 先回退一小步然后加速前进
    anticipate_overshoot_interpolator 在上一个基础上超出终点一小步再回到终点
    bounce_interpolator 最后阶段弹球效果
    cycle_interpolator 周期运动
    linear_interpolator 匀速
    overshoot_interpolator 快速到达终点并超出一小步最后回到终点
    浮点型值:

    fromXScale 属性为动画起始时 X坐标上的伸缩尺寸
    toXScale 属性为动画结束时 X坐标上的伸缩尺寸

    fromYScale 属性为动画起始时Y坐标上的伸缩尺寸
    toYScale 属性为动画结束时Y坐标上的伸缩尺寸

    说明:
    以上四种属性值

    0.0表示收缩到没有
    1.0表示正常无伸缩
    值小于1.0表示收缩
    值大于1.0表示放大

    pivotX 属性为动画相对于物件的X坐标的开始位置
    pivotY 属性为动画相对于物件的Y坐标的开始位置

    说明:
    以上两个属性值 从0%-100%中取值
    50%为物件的X或Y方向坐标上的中点位置

    长整型值:
    duration 属性为动画持续时间
    说明: 时间以毫秒为单位

    布尔型值:
    fillAfter 属性 当设置为true ,该动画转化在动画结束后被应用
    -->
  • 中间电池图标的旋转动画

    电池图标

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <ImageView
    android:id="@+id/t1_icon2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/t1_icon1"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30.0dip"
    android:src="@mipmap/tutorial1_icon3"
    android:visibility="visible" />

    加载并开始动画

    1
    2
    3
    4
    5
    6
    Animation animation1 = AnimationUtils.loadAnimation(MainActivity.this, R.anim.tutorail_rotate);
    LinearInterpolator lin = new LinearInterpolator();
    animation1.setInterpolator(lin);

    t1_icon2.setVisibility(View.VISIBLE);
    t1_icon2.startAnimation(animation1);

    关于旋转动画的描述,刚开始的时候,电池图标是从无到有的一个从小到大的scale,android:fromXScale=”0.0”到1.2,然后就结束了,同时会无限的旋转,rotate,从0度到359度旋转,时间为3000ms,pivotX,Y 50%表示从以中心点旋转

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android" >

    <scale
    android:duration="800"
    android:fillAfter="false"
    android:fromXScale="0.0"
    android:fromYScale="0.0"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1.2"
    android:toYScale="1.2" />

    <rotate
    android:duration="3000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="-1"
    android:toDegrees="359.0" />
    <!-- rotate 旋转动画效果
    属性:interpolator 指定一个动画的插入器

    浮点数型值:
    fromDegrees 属性为动画起始时物件的角度
    toDegrees 属性为动画结束时物件旋转的角度 可以大于360度


    说明:
    当角度为负数——表示逆时针旋转
    当角度为正数——表示顺时针旋转
    (负数from——to正数:顺时针旋转)
    (负数from——to负数:逆时针旋转)
    (正数from——to正数:顺时针旋转)
    (正数from——to负数:逆时针旋转)

    pivotX 属性为动画相对于物件的X坐标的开始位置
    pivotY 属性为动画相对于物件的Y坐标的开始位置

    说明: 以上两个属性值 从0%-100%中取值
    50%为物件的X或Y方向坐标上的中点位置

    长整型值:
    duration 属性为动画持续时间
    说明: 时间以毫秒为单位
    -->

    </set>
  • 电池图片数字的闪烁变换

    闪烁的图片

    1
    2
    3
    4
    5
    6
    7
    <ImageView
    android:id="@+id/t1_icon1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="180.0dip"
    android:layout_marginTop="53.0dip"
    android:background="@drawable/t1_frame_animation" />

    图片定义t1_frame_animation.xml,animation-list实现的是逐帧动画,oneshot表示不停的循环播放,每个帧的图片和时长定义

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false" >
    <!--
    根标签为animation-list,其中oneshot代表着是否只展示一遍,设置为false会不停的循环播放动画
    根标签下,通过item标签对动画中的每一个图片进行声明
    android:duration 表示展示所用的该图片的时间长度
    -->
    <item
    android:drawable="@mipmap/tutorial1_icon1"
    android:duration="200"/>
    <item
    android:drawable="@mipmap/tutorial1_icon2"
    android:duration="200"/>

    </animation-list>

    开始启动动画

    1
    2
    3
    4
    t1_icon1.setImageResource(R.drawable.t1_frame_animation);
    t1_icon1_animationDrawable = (AnimationDrawable) t1_icon1.getDrawable();

    t1_icon1_animationDrawable.start();
  • 最下角箭头下移和透明度变换

    底部箭头

    1
    2
    3
    4
    5
    6
    7

    <ImageView
    android:id="@+id/t1_next"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20.0dip"
    android:src="@mipmap/tutorial_next" />

    加载动画

    1
    animationBottom = AnimationUtils.loadAnimation(MainActivity.this, R.anim.tutorail_bottom);

    启动

    1
    t1_next.startAnimation(animationBottom);

    动画描述文件tutorail_bottom.xml,转移动画和透明度的组合

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
    android:repeatMode="reverse" >

    <translate
    android:duration="1000"
    android:fromXDelta="0"
    android:fromYDelta="-15"
    android:repeatCount="infinite"
    android:toXDelta="0"
    android:toYDelta="20" />
    <!-- translate 平移动画效果
    整型值:
    fromXDelta 属性为动画起始时 X坐标上的位置
    toXDelta 属性为动画结束时 X坐标上的位置
    fromYDelta 属性为动画起始时 Y坐标上的位置
    toYDelta 属性为动画结束时 Y坐标上的位置
    注意:
    没有指定fromXType toXType fromYType toYType 时候,
    默认是以自己为相对参照物 ,默认参考物最重要
    长整型值:
    duration 属性为动画持续时间
    说明: 时间以毫秒为单位
    -->

    <alpha
    android:duration="1000"
    android:fromAlpha="1.0"
    android:repeatCount="infinite"
    android:toAlpha="0.3" />
    <!--
    透明度控制动画效果 alpha
    浮点型值:
    fromAlpha 属性为动画起始时透明度
    toAlpha 属性为动画结束时透明度
    说明:
    0.0表示完全透明
    1.0表示完全不透明
    以上值取0.0-1.0之间的float数据类型的数字

    长整型值:
    duration 属性为动画持续时间
    说明:
    时间以毫秒为单位
    整型值:
    repeatCount:重复次数
    说明:
    infinite:循环执行,
    具体正整数表示循环次数

    repeatMode:重复模式,
    说明:
    restart:重新从头开始执行
    reverse:反方向执行

    -->

    </set>

其他页面的也都差不多原理实现

第三页分析

可以看一下火箭飞后面云朵的动画

每个云朵都是一个image view

1
2
3
4
5
6
7
8
9
10
<ImageView
android:id="@+id/t3_icon3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="120.0dip"
android:layout_marginTop="45.0dip"
android:src="@mipmap/t3_could_left2"
android:visibility="invisible"/>

启动动画

1
t3_icon2.startAnimation(transAnimation2);

动画定义

1
2
3
4
5
6
7
8
9
10
11
12
final TranslateAnimation transAnimation2 = new TranslateAnimation(fx1, tx1, fy1, ty1);
transAnimation2.setDuration(800);
transAnimation2.setRepeatCount(Animation.INFINITE);
transAnimation2.setRepeatMode(Animation.RESTART);
lin = new LinearInterpolator();
transAnimation2.setInterpolator(lin);

final TranslateAnimation transAnimation3 = new TranslateAnimation(fx2, tx2, fy2, ty2);
transAnimation3.setDuration(1200);
transAnimation3.setRepeatCount(Animation.INFINITE);
transAnimation3.setRepeatMode(Animation.RESTART);
transAnimation3.setInterpolator(lin);

每个云朵的移动速度不一样,其实位置fx1,fy1到目标位置tx1,ty1也不一样

第四页分析

挂牌左右摇晃动画

挂牌

1
2
3
4
5
6
<ImageView
android:id="@+id/t4_icon1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/t4_image"
android:visibility="visible" />

左右摇晃动画

1
2
3
4
5
6
7
8
int pivot = Animation.RELATIVE_TO_SELF;
CycleInterpolator interpolator = new CycleInterpolator(3.0f);//执行多少次
RotateAnimation animation = new RotateAnimation(0, 10, pivot, 0.47f, pivot, 0.05f);
animation.setStartOffset(500);
animation.setDuration(3000);
animation.setRepeatCount(1);// Animation.INFINITE
animation.setInterpolator(interpolator);
t4_icon1.startAnimation(animation);

其他基本都是类似的实现:

小结

以上动画使用了Android的基本动画类型alpha,rotate,scale,translate,另外引入插值器完成动画

下面火箭的上升有一个自定义属性动画,我们现认识一下,后续在细细学习分析

火箭的上升动画

火箭view

1
2
3
4
5
6
7
8
<ImageView
android:id="@+id/page_one_rocket"
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@mipmap/image_one_rocket"
android:layout_below="@+id/page_one_center_bg"
android:layout_toLeftOf="@+id/center"
android:layout_marginRight="30dp"/>

加载动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
animationRocket = ArcAnimator.createArcAnimator(page_one_rocket, centerX + r - x*3/2 + 20, centerY - r + 3*x/4 - 20 , 90f, Side.RIGHT);
animationRocket.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}

@Override
public void onAnimationEnd(Animator animation) {
page_one_center_tj.startAnimation(animationCenterTJ);
}

@Override
public void onAnimationCancel(Animator animation) {
}

@Override
public void onAnimationRepeat(Animator animation) {
}
});
animationRocket.setDuration(1500);
animationRocket.start();

其中 ArcAnimator是自定义的属性动画

路径示意图

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package cn.lry.animation.arcanimator;



import android.view.View;
import android.view.animation.Interpolator;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;

import java.lang.ref.WeakReference;

public class ArcAnimator extends Animator {

public static ArcAnimator createArcAnimator(View clipView, View nestView, float degree, Side side){
return createArcAnimator(clipView, Utils.centerX(nestView), Utils.centerY(nestView), degree, side);
}

public static ArcAnimator createArcAnimator(View clipView, float endX, float endY, float degree, Side side){
ArcMetric arcMetric = ArcMetric.evaluate(Utils.centerX(clipView), Utils.centerY(clipView), endX, endY, degree, side);
return new ArcAnimator(arcMetric, clipView);
}

ArcMetric mArcMetric;
WeakReference<View> mTarget;
WeakReference<ObjectAnimator> mAnimator;
float mValue;


private ArcAnimator(ArcMetric arcmetric, View target) {
mArcMetric = arcmetric;
mTarget = new WeakReference<>(target);

mAnimator = new WeakReference<>(
ObjectAnimator.ofFloat(
ArcAnimator.this, // target
"degree", // property
arcmetric.getStartDegree(),
arcmetric.getEndDegree())
);//其实主要就是一个ObjectAnimator,关注的是degree的值
}

void setDegree(float degree){
mValue = degree;
View clipView = mTarget.get();
float x = mArcMetric.getAxisPoint().x + mArcMetric.mRadius * Utils.cos(degree);
float y = mArcMetric.getAxisPoint().y - mArcMetric.mRadius * Utils.sin(degree);
ViewHelper.setX(clipView,x - clipView.getWidth() / 2);
ViewHelper.setY(clipView,y - clipView.getHeight() / 2);
}

float getDegree(){
return mValue;
}

@Override
public long getStartDelay() {
Animator a = mAnimator.get();
return a == null ? 0 : a.getDuration();
}

@Override
public void setStartDelay(long startDelay) {
Animator a = mAnimator.get();
if(a != null) a.setStartDelay(startDelay);
}

@Override
public ArcAnimator setDuration(long duration) {
Animator a = mAnimator.get();
if(a != null) a.setDuration(duration);
return this;
}

@Override
public long getDuration() {
Animator a = mAnimator.get();
return a == null ? 0 : a.getDuration();
}

@Override
public void setInterpolator(Interpolator value) {
Animator a = mAnimator.get();
if(a != null) a.setInterpolator(value);
}

@Override
public void start() {
super.start();
Animator a = mAnimator.get();
if(a != null) a.start();
}

@Override
public void end() {
super.end();
Animator a = mAnimator.get();
if(a != null) a.end();
}

@Override
public void cancel() {
super.cancel();
Animator a = mAnimator.get();
if(a != null) a.cancel();
}

@Override
public void addListener(AnimatorListener listener) {
Animator a = mAnimator.get();
if(a != null) a.addListener(listener);
}

@Override
public void setupEndValues() {
super.setupEndValues();
Animator a = mAnimator.get();
if(a != null) a.setupEndValues();
}

@Override
public void setupStartValues() {
super.setupStartValues();
Animator a = mAnimator.get();
if(a != null) a.setupStartValues();
}

@Override
public boolean isRunning() {
Animator a = mAnimator.get();
return a != null && a.isRunning();
}

@Override
public String toString() {
return mArcMetric.toString();
}
}

关注一下

1
ArcAnimator.createArcAnimator(page_one_rocket, centerX + r - x*3/2 + 20, centerY - r + 3*x/4 - 20 , 90f, Side.RIGHT);

centerX + r - x*3/2 + 20centerY - r + 3*x/4 - 20是计算出来火箭图标的最终目标位置的x,y坐标

看几条路线轨迹

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
01-10 04:57:03.822 11717-11717/cn.lry.animation I/GuideActivity: r=270.0中间背景的长宽
01-10 04:57:03.822 11717-11717/cn.lry.animation I/GuideActivity: x=120.0火箭图标的长宽
这两个只是用来算目标位置的坐标

01-10 04:57:03.832 11717-11717/cn.lry.animation I/ArcAnimator: createArcAnimator endx=349.0 endy=217.0degree90.0side =RIGHT
计算出目标位置的坐标为349,217

01-10 04:57:03.845 11717-11717/cn.lry.animation I/ArcAnimator: createArcAnimator starx=74.0 starty=381.0
当前位置的坐标,最后还进行了中心计算

01-10 04:57:03.884 11717-11717/cn.lry.animation I/ArcAnimator: setDegree=0.0

01-10 04:57:03.885 11717-11717/cn.lry.animation I/ArcAnimator: x=134.00002===ArcM.x + ArcM.r * cos(-88.82553): 129.5 + 219.54613 * 0.020496916
01-10 04:57:03.886 11717-11717/cn.lry.animation I/ArcAnimator: y=441.0===ArcM.y + ArcM.r * sin(-88.82553): 221.5 + 219.54613 * -0.9997899
01-10 04:57:03.887 11717-11717/cn.lry.animation I/ArcAnimator: setviewX=74.000015
01-10 04:57:03.887 11717-11717/cn.lry.animation I/ArcAnimator: setviewy=381.0
第一次偏移,当前

01-10 04:57:03.917 11717-11717/cn.lry.animation I/ArcAnimator: setDegree=-88.82553
01-10 04:57:03.919 11717-11717/cn.lry.animation I/ArcAnimator: x=134.00002===ArcM.x + ArcM.r * cos(-88.82553): 129.5 + 219.54613 * 0.020496916
01-10 04:57:03.920 11717-11717/cn.lry.animation I/ArcAnimator: y=441.0===ArcM.y + ArcM.r * sin(-88.82553): 221.5 + 219.54613 * -0.9997899
01-10 04:57:03.920 11717-11717/cn.lry.animation I/ArcAnimator: setviewX=74.000015
01-10 04:57:03.920 11717-11717/cn.lry.animation I/ArcAnimator: setviewy=381.0
01-10 04:57:03.965 11717-11717/cn.lry.animation I/ArcAnimator: setDegree=-88.82553
01-10 04:57:03.966 11717-11717/cn.lry.animation I/ArcAnimator: x=134.83453===ArcM.x + ArcM.r * cos(-88.60769): 129.5 + 219.54613 * 0.024298022
01-10 04:57:03.967 11717-11717/cn.lry.animation I/ArcAnimator: y=440.98132===ArcM.y + ArcM.r * sin(-88.60769): 221.5 + 219.54613 * -0.9997048

轨迹的示意图大概如下,90度是一个四分之一圆弧,180度就是一个半圆弧