前面一篇文章Navigator 过渡动画卡顿的解决方案,提到了 InteractionManager.runAfterInteractions
这个解决方案。
InteractionManager
Interactionmanager可以将一些耗时较长的工作安排到所有互动或动画完成之后再进行。这样可以保证JavaScript动画的流畅运行。
应用这样可以安排一个任务在交互和动画完成之后执行:
InteractionManager.runAfterInteractions(() => {
// ...耗时较长的同步的任务...
});
把这个和其他的延迟计划函数对比:
requestAnimationFrame(): 用来执行在一段时间内控制视图动画的代码
setImmediate/setTimeout/setInterval(): 在稍后执行代码。注意这有可能会延迟当前正在进行的动画。
runAfterInteractions(): 在稍后执行代码,不会延迟当前进行的动画。
触摸处理系统会把一个或多个进行中的触摸操作认定为'交互',并且会将runAfterInteractions()的回调函数延迟执行,直到所有的触摸操作都结束或取消了。
InteractionManager还允许应用注册动画,在动画开始时创建一个交互“句柄”,然后在结束的时候清除它。
var handle = InteractionManager.createInteractionHandle();
// 执行动画... (`runAfterInteractions`中的任务现在开始排队等候)
// 在动画完成之后
InteractionManager.clearInteractionHandle(handle);
// 在所有句柄都清除之后,现在开始依序执行队列中的任务
runAfterInteractions接受一个普通的回调函数,或是一个PromiseTask对象,该对象需要带有名为gen的方法,并返回一个Promise。如果提供的参数是一个PromiseTask, 那么即便它是异步的它也会阻塞任务队列,直到它(以及它所有的依赖任务,哪怕这些依赖任务也是异步的)执行完毕后,才会执行下一个任务。
但是在后面的测试过程中,发现其有不触发回调的地方,场景是这样:
从A跳到B页面,然后使用手势左滑退出到A,然后再从A跳到B页面发现runAfterInteractions不再触发了,猜测是InteractionManager认为手势的交互还没结束不算完成,所以不触发回调。那么该怎么解决呢?
1.从手势交互(PanResponder)那里入手,清除句柄
InteractionManager.clearInteractionHandle(this._panResponder.getInteractionHandle());
//没去深入实现
2.自己加定时器,保证runAfterInteractions在多长时间内必须触发一次
重新自定义InteractionManager
import { InteractionManager } from 'react-native'
export default {
...InteractionManager,
runAfterInteractions: f => {
// ensure f get called, timeout at 500ms
// @gre workaround https://github.com/facebook/react-native/issues/8624
let called = false;
const timeout = setTimeout(() => {
called = true;
f();
}, 500);
InteractionManager.runAfterInteractions(() => {
if (called) return;
clearTimeout(timeout);
f();
});
}
}
--------------------------------------------------------------------------------
使用示例
import React, { Component } from 'react'
import InteractionManager from '../component/InteractionManager'
//自定义InteractionManager的路径
export default class BaseComponent extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
......
})
}
}