[Gankly] View animate cancel 无效
Gankly
基于干货Api、妹子图做的一个应用。应用包含干货 androi 、ios 、妹子,其他还有几个模块,包括新鲜事(煎蛋)、科技资讯、团队博客,以及抓包获取百思不得姐接口,做了视频跟给图片这2个模块。有兴趣的朋友,可以访问这个开源项目,如果有什么问题,可以留言,也可以联系我。
项目地址: https://github.com/leftcoding/GankLy
写这个文章的目的,因为在做这个项目中,总会碰到一些问题。所以,我觉得有必要把自己碰到的问题,解决问题的方法,写在以后的文章中,让其他碰到同样问题的人,少走一些冤枉路。
项目中要实现一个效果,就是一个提示框,从右向左滑动,之后再从左往右消失。类似图下:

看到图的第一个反映就是用动画来实现。因为项目是支持5.0+。所以,直接用新的代码段来实现。
布局
</RelativeLayout>
<RelativeLayout
android:id="@+id/browse_rl_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/item_author_bg">
<TextView
android:id="@+id/progress_txt_page"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ImageView
android:id="@+id/brose_img_auto"
style="@style/Widget.AppCompat.ActionButton.Overflow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
<TextView
android:id="@+id/browse_txt_auto_tip"
android:layout_width="180dp"
android:layout_height="40dp"
android:layout_above="@id/browse_rl_navigation"
android:layout_marginEnd="-180dp"
android:layout_toEndOf="@id/browse_rl_navigation"
android:background="@drawable/item_author_bg"
android:gravity="center"
android:padding="8dp"
android:text="@string/gralley_auto_tip"
android:textColor="?attr/colorAccent"
android:textSize="@dimen/normalSize" />
</RelativeLayout>
GalleryActivity
txtAutoTip.animate().translationX(-getTipWidth).setDuration(300).setListener(newAnimator.AnimatorListener() {
@Override
public voidonAnimationStart(Animatoranimation) {
txtAutoTip.setAlpha(1);
}
@Override
public voidonAnimationEnd(Animatoranimation) {
// 之后从左往右动画
txtAutoTip.animate().alpha(0).translationX(0).setDuration(3000).setListener().start();
}
@Override
public voidonAnimationCancel(Animatoranimation) {
}
@Override
public voidonAnimationRepeat(Animatoranimation) {
}
}).start();
这样就写好代码了,实现起来也达到了效果,但是,如果用户这个时候点击返回键或者关闭activity,那么,就会出现空指针

这个是我在activity ondestory方法
@Override
protected void onDestroy() {
// 当activity 结束时,退出动画
txtAutoTip.animate().cancel();
super.onDestroy();
}
但是为什么View 是空指针呢?
只有一个问题,就是当activity 结束时,View 的取消动画根本没有执行到,所以导致空指针。那么就来看下为什么取消没有效果。
我们先从View animate方法开始看。找到源码

这就是 new 一个 ViewPropertyAnimator 对象,然后我们找到 ViewPropertyAnimator 的 cancel 方法。

看到这里,Animator runningAnim.cancel(); 就知道了,有关于动画的取消都在这里。
然后看代码知道,这是foreach循环,那么来源就是mAnimatorMap。
找到mAnimatorMap 数组添加的代码。

添加元素在 startAnimation 方法中。那么startAnimation方法,在哪里调用呢?
![]$4$%35BPN`H.png](https://img.haomeiwen.com/i1450309/847e2c3cc1f10294.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
原来在 start 的时候,就开始调用了 startAnimation ,也就是在view.animate().start();的时候就把这个动画元素添加到数组里,这样就比较清楚了。
往回继续看看 startAnimation 方法,添加的是ValueAnimator 对象。那么,我就去ValueAnimator 对象中。找到 cancel 方法。

这里 mListeners 数组循环调用 AnimatorListener 的 onAnimationCancel 方法。那我们查找 mListeners 数组的来源,发现在 ValueAnimator 类中,并没有mListeners 数组,那么就有可能,数组来于是父类中。那么去父类看看。

父类是 Animator。

进去 Animator 发现果然有 mListeners 数组,看看数组初添加。

发现数组添加是在 addListener 方法中。那么哪里调用 addListener 方法呢?这个时候,就回到最开始添加这个ValueAnimator 对象的地方,那么就是在一开始就提到的ViewPropertyAnimator对象的startAnimation方法中。ValueAnimator,调用addListener方法添加AnimatorListener接口。那么也就是mAnimatorEventListener这个类。

那我们来看看mAnimatorEventListener类。

在ViewPropertyAnimator类,一开始就初始化好了。看下这个类的onAnimationCancel方法。

可以发现当 mListener != null的时候才执行。那么mListener 设置时候

也就是View.animate().setListener() 的时候
所以最后也就说,没有setListener,那么View animate cancel 设置是没有效果的。
最后想说。有兴趣的可以看看我的项目 。