lottie android min sdk,跳一个Lottie无法回调开始播放动画事件的坑

一、背景介绍

项目背景是在界面中弹出一个浮层动画,同时播放一个音效。

二、当前实现

实现思路比较简单:继承一个DialogFragment,在相关的生命周期方法onViewCreated中调用startLottieAnim进行动画播放,同时监听lottie动画播放的回调事件,在动画开始播放时播放音效文件;动画播放结束时关闭DialogFragment。

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

29private void startLottieAnim(String assetFolder, final Uri voiceUri){

lottieAnimationView.setImageAssetsFolder(assetFolder + "/images");

lottieAnimationView.setAnimation(assetFolder + "/anim.json");

lottieAnimationView.setRepeatCount(0);

lottieAnimationView.addAnimatorListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation){

playAnimVoice(voiceUri);

}

@Override

public void onAnimationEnd(Animator animation){

stopAnimVoice();

dismiss();

}

@Override

public void onAnimationCancel(Animator animation){

stopAnimVoice();

dismiss();

}

@Override

public void onAnimationRepeat(Animator animation){

playAnimVoice(voiceUri);

}

});

lottieAnimationView.playAnimation();

}

三、发现问题

对于以上的代码,实际运行起来会发现动画播放的同时并不能播放音频,而且播放结束也不会自动消失。也就是说onAnimationStart和onAnimationEnd方法并没有被回调。这是为什么呢?看lottie实现源码 (BaseLottieAnimator),会发现

1

2

3

4

5

6

7

8

9void notifyStart(boolean isReverse){

for (Animator.AnimatorListener listener : listeners) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

listener.onAnimationStart(this, isReverse);

} else {

listener.onAnimationStart(this);

}

}

}

1

2

3

4

5

6

7

8void notifyEnd(boolean isReverse){

for (Animator.AnimatorListener listener : listeners) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

listener.onAnimationEnd(this, isReverse);

} else {

listener.onAnimationEnd(this);

}

}

在通知动画开始和结束的时候,会根据系统版本决定走哪个方法,这里需要注意方法签名。由于之前代码只写了一个参数的方法回调,因此在Android O及以上版本中会走另一个方法回调。因此,首先想到需要在注册的AnimatorListener中添加之前遗漏的两个方法回调。

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{

lottieAnimationView.setImageAssetsFolder(assetFolder + "/images");

lottieAnimationView.setAnimation(assetFolder + "/anim.json");

lottieAnimationView.setRepeatCount(0);

lottieAnimationView.addAnimatorListener(new Animator.AnimatorListener() {

@Override

public void onAnimationStart(Animator animation){

playAnimVoice(voiceUri);

}

@Override

public void onAnimationStart(Animator animation, boolean isReverse){

playAnimVoice(voiceUri);

}

@Override

public void onAnimationEnd(Animator animation){

stopAnimVoice();

dismiss();

}

@Override

public void onAnimationEnd(Animator animation, boolean isReverse){

stopAnimVoice();

dismiss();

}

@Override

public void onAnimationCancel(Animator animation){

stopAnimVoice();

dismiss();

}

@Override

public void onAnimationRepeat(Animator animation){

playAnimVoice(voiceUri);

}

});

lottieAnimationView.playAnimation();

}

修改之后运行会发现,动画播放结束的回调事件成功接收了,但是音效依然无法播放。也就是onAnimationStart方法依然未被回调。继续看下源码:在LottieAnimationView.java中

1

2

3

4

5

6

7

8public void playAnimation(){

if (isShown()) {

lottieDrawable.playAnimation();

enableOrDisableHardwareLayer();

} else {

wasAnimatingWhenNotShown = true;

}

}

如果isShown判断成功,会继续走LottieDrawable.java中的

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18public void playAnimation(){

if (compositionLayer == null) {

lazyCompositionTasks.add(new LazyCompositionTask() {

@Override

public void run(LottieComposition composition){

playAnimation();

}

});

return;

}

if (systemAnimationsEnabled || getRepeatCount() == 0) {

animator.playAnimation();

}

if (!systemAnimationsEnabled) {

setFrame((int) (getSpeed() < 0 ? getMinFrame() : getMaxFrame()));

}

}

进而走到LottieValueAnimator.java中的playAnimation

1

2

3

4

5

6

7

8

9@MainThread

public void playAnimation(){

running = true;

notifyStart(isReversed());

setFrame((int) (isReversed() ? getMaxFrame() : getMinFrame()));

lastFrameTimeNs = 0;

repeatCount = 0;

postFrameCallback();

}

在这里看到了熟悉的notifyStart方法。可是我们并没有收到对应的回调,可以想到LottieAnimationView.java中并没有走isShown判断分支,也就是说走了

1

2

3

4

5

6

7

8public void playAnimation(){

if (isShown()) {

lottieDrawable.playAnimation();

enableOrDisableHardwareLayer();

} else {

wasAnimatingWhenNotShown = true;

}

}

只是标记了一个状态,标明lottie动画还未显示出来。那它为什么后来又能播放动画呢?在LottieAnimationView.java中有监听可见性回调的方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19protected void onVisibilityChanged(@NonNull View changedView, int visibility){

// This can happen on older versions of Android because onVisibilityChanged gets called from the

// constructor of View so this will get called before lottieDrawable gets initialized.

// https://github.com/airbnb/lottie-android/issues/1143

if (lottieDrawable == null) {

return;

}

if (isShown()) {

if (wasAnimatingWhenNotShown) {

resumeAnimation();

wasAnimatingWhenNotShown = false;

}

} else {

if (isAnimating()) {

pauseAnimation();

wasAnimatingWhenNotShown = true;

}

}

}

当lottieview从不可见到可见时,会根据wasAnimatingWhenNotShown之前记录的这个状态去resumeAnimation。在resumeAnimation方法一路跟下去最后会走到LottieValueAnimator.java的

1

2

3

4

5

6

7

8

9

10public void resumeAnimation(){

running = true;

postFrameCallback();

lastFrameTimeNs = 0;

if (isReversed() && getFrame() == getMinFrame()) {

frame = getMaxFrame();

} else if (!isReversed() && getFrame() == getMaxFrame()) {

frame = getMinFrame();

}

}

这里可以发现并没有像startAnimation那样的notifyXXX的回调方法了。因此我们收不到onAnimationStart的方法回调了。

至此弄清楚了异常的原因,如何修改就很简单了。现在已经能猜到是布局加载之后,lottieview还没有渲染出来我们就去startAnimation导致回调无法走到,因此我们可以通过对lottieView进行post或者通过监听viewTreeObserver的事件再进行startPlayAnimation操作就行了。

四、总结

1、回调方法要写完整;

2、如果弹框一开始就要显示lottie动画,需要等ui控件可见之后再播放动画

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/345920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ad-hoc

Ad-hoc这个词来源于拉丁语&#xff0c;在百度上解释为“for this purpose only”&#xff0c;在wiki上解释为“for this”&#xff0c;其中文在wiki上被解释成包含特设的、特定目的的&#xff08;地&#xff09;、即席的、临时的、将就的、专案的”这么多种含义。在wireless ne…

掌握Java 11的Constantdynamic

为了使JVM对动态语言更具吸引力&#xff0c;该平台的第七版已将invokedynamic引入了其指令集。 Java开发人员通常不会注意到此功能&#xff0c;因为它隐藏在Java字节码中。 简而言之&#xff0c;通过使用invokedynamic &#xff0c;可以将方法调用的绑定延迟到第一次调用之前。…

android5.0 v4a,【图】多图讲解V4A提高G5音效详细步骤(G5音效可以更棒的)

首先感谢论坛前辈&#xff0c;看着你们介绍的方法&#xff0c;我把G5应有的音效搞出来了&#xff0c;效果提升非常明显。(看清了&#xff0c;如果不是非常明显&#xff0c;我也不会费这么大劲在这儿做讲解)。特记录和总结过程如下&#xff1a;1. 安装一键ROOT。2. 安装虚拟按…

feeder link

feeder link&#xff1a; 从一个设在指定的固定点上的地球站到一个空间站&#xff0c;或从一个空间站到一个设在某固定点的地球站的无线电链路&#xff0c;用于除卫星固定业务以外的空间无线电通信业务的

2021年春季学期期末统一考试 中国法制史 试题

2021年7月 一、单项选择题&#xff08;每小题2分&#xff0c;共20分&#xff09; 1.商朝法律制度的总称叫做( )。 A.禹刑 B.汤刑 C.汤诰 D.九刑 2.战国时期改“法”为“律”的人是( )。 A.韩非 B.赵鞅 C.商鞅 D.屈原 3.秦始皇和李斯等人取消了世卿世禄分封制&#xff0c;在全国…

怎么在html中加入pjax,pjax加载多说的三种方法

多说官方提供的方法&#xff1a;http://dev.duoshuo.com/docs/50b344447f32d30066000147这里不进行说明&#xff0c;请进入上述链接进行查看。效果说明&#xff1a;进入文章页需要点击按钮&#xff0c;多说评论才会加载出来。方法二民间高手不满足方法一那种需要按一次才能加载…

2021年春季学期期末统一考试 高级财务会计 试题

试卷代号&#xff1a; 1039 2021年7月 注意事项 一、将你的学号、姓名及分校&#xff08;工作站&#xff09;名称填写在答题纸的规定栏内。考试结束后&#xff0c;把试卷和答题纸放在桌上。试卷和答题纸均不得带出考场。监考人收完考卷和答题纸后才可离开考场。 二、仔细读懂题…

Multi-commodity Flow Problem

多物网络流问题&#xff08;Multi-commodity Flow Problem&#xff09;是多种物品&#xff08;或货物&#xff09;在网络中从不同的源点流向不同的汇点的网络流问题。 定义

2021年春季学期期末统.考试 公司概论 试题

试卷代号&#xff1a; 1040 2021年7月 注意事项 一、将你的学号、姓名及分校&#xff08;工作站&#xff09;名称填写在答题纸的规定栏内。考试结束后&#xff0c;把试卷和答题纸放在桌上。试卷和答题纸均不得带出考场。监考人收完考卷和答题纸后才可离开考场。 二、仔细读懂题…

生产替代物料_一种替代的多生产者方法

生产替代物料最近在InfoQ上&#xff0c;Aliasei Papou发表了一篇关于他的一些实验的文章 &#xff0c;该实验在线程之间进行了高性能的消息交换。 本文中有许多示例&#xff0c;但我将重点介绍多生产者案例。 文章显示的一种优化方法是&#xff0c;如果您知道初始化时拥有的生产…

2021年春季学期期末统一考试 金融统计分析 试题(开卷)

试卷代号&#xff1a; 1013 2021年7月 一、单项选择题&#xff08;每小题2分&#xff0c;共40分。每小题有一项答案正确&#xff0c;请将正确答案的序号填在括号内&#xff09; 1.以下属于商业银行被动负债的是( )。 A.发行债券 B.同业拆借 C.向中央银行借款 D.存款性负债 2.国…

js清除添加的下拉框html,Html下拉框的定义以及JS、Jquary取值、添加和移除

现在有一idtest的下拉框&#xff0c;怎么拿到选中的那个值呢&#xff1f;分别使用javascript原生的方法和jquery方法//multiply设置可以多行显示&#xff0c;size设置默认显示多少行。text1text2code:一&#xff1a;javascript原生的方法1:拿到select对象&#xff1a; var mys…

信干噪比、信噪比

信干噪比 名词定义 信干噪比SINR&#xff08;Signal to Interference plus Noise Ratio&#xff09;&#xff0c;指的是系统中信号与干扰和噪声之和的比。 信号是指来自设备外部需要通过设备进行处理的电子信号。 干扰是指系统本身以及异系统带来的干扰&#xff0c;如同频干扰…

MicroProfile在Jakarta EE时代的作用

自创建以来&#xff0c;MicroProfile赢得了广泛的关注&#xff0c;并制定了各种规格。 最初&#xff0c;它的创建是为了在多个供应商的推动下&#xff0c;以更快的速度推进微服务世界的企业Java。 现在&#xff0c;随着在Eclipse Foundation下将Java EE转换为Jakarta EE&#x…

矢量图标库如何引入html,Iconfont矢量图标库在网站中的使用方法

原标题&#xff1a;Iconfont矢量图标库在网站中的使用方法大家都知道现在移动端网站设计比较热门&#xff0c;由于移动端的网站页面的收缩性要求很高&#xff0c;必然在网页设计中&#xff0c;一些小点的图标&#xff0c;使用图片收缩性&#xff0c;以及美观上并不是很理想&…

2021年春季学期期末统一考试 劳动与社会保障法(本) 试题

试卷代号&#xff1a; 1021 2021年7月 一、单项选择题&#xff08;每小题1分&#xff0c;共10分。在每小题的四个备选答案中&#xff0c;选出一个正确的答案&#xff0c;请将正确答案的序号填在括号内&#xff09; 1.劳动者的劳动权利能力和劳动行为能力一般开始于( )。 A.14周…

弗林斯传输公式、天线温度

这是被称为弗林斯传输公式。这个等式关系 自由空间路径损耗&#xff0c;天线增益和波长 接收和发射功率。这是一个基本 在天线理论方程&#xff0c;应该记住的&#xff08;以及 上述推导&#xff09;。 弗林斯传输方程的另一种有用的形式是给定的公式[2]。自 波长和频率&#…

2021年春季学期期末统一考试 成本管理 试题

试卷代号&#xff1a; 1032 2021年7月 一、单项选择题&#xff08;本类题共20分&#xff0c;每小题2分&#xff09; 1.交互分配法一般在( )分配中使用。 A.直接材料费用 B.辅助生产费用 C.直接工资 D.在产品成本 2.采用品种法进行成本计算时其成本计算期是( )。 A.定期于期末计…

html 垂直线代码,html – Bootstrap 3水平和垂直分隔线

你必须使用Bootstrap吗&#xff1f;这是一个基本的HTML / CSS示例&#xff0c;用于获取不使用任何Bootstrap的外观&#xff1a;HTML&#xff1a;Rich Media Ad ProductionWeb Design & DevelopmentMobile Apps DevelopmentCreative DesignWeb AnalyticsSearch Engine Marke…

马尔可夫决策过程 Markov decision process MDP, 连续时间Markov chain, CMDP(全)

引言 在概率论及统计学中&#xff0c;马尔可夫过程&#xff08;英语&#xff1a;Markov process&#xff09;是一个具备了马尔可夫性质的随机过程&#xff0c;因为俄国数学家安德雷马尔可夫得名。马尔可夫过程是不具备记忆特质的&#xff08;memorylessness&#xff09;。换言…