React Fiber 手势调度器
作用
导出的类型
预定手势
// This type keeps track of any scheduled or active gestures.
// 这个类型用于跟踪任何已安排或正在进行的手势。
export type ScheduledGesture = {
provider: GestureTimeline;
// The number of times this same provider has been started.
// 这个相同提供者被启动的次数。
count: number;
// The percentage along the timeline where the "current" state starts.
// 时间轴上“当前”状态开始的百分比。
rangeStart: number;
// The percentage along the timeline where the "destination" state is reached.
// 达到“目标”状态时在时间线上所占的百分比。
rangeEnd: number;
// Any addTransitionType call made during startGestureTransition.
// 在 startGestureTransition 期间进行的任何 addTransitionType 调用。
types: null | TransitionTypes;
// Used to cancel the running transition after we're done.
// 用于在完成后取消正在运行的过渡。
running: null | RunningViewTransition;
// Callback to run to commit if there's a pending commit.
// 如果有待处理的提交,运行以提交的回调。
commit: null | (() => void);
// If the gesture was released in a committed state and should actually commit.
// 如果手势在已提交状态下被释放,实际上应该提交。
committing: boolean;
// The Lane that we'll use to schedule the revert.
// 我们将用于安排还原的通道。
revertLane: Lane;
// The previous scheduled gesture in the queue for this root.
// 该根节点队列中之前安排的手势。
prev: null | ScheduledGesture;
// The next scheduled gesture in the queue for this root.
// 该根的队列中下一个预定的手势。
next: null | ScheduledGesture;
};
手势调度
备注
ensureRootIsScheduled()由 ReactFiberRootScheduler#ensureRootIsScheduled 实现
export function scheduleGesture(
root: FiberRoot,
provider: GestureTimeline,
): ScheduledGesture {
let prev = root.pendingGestures;
while (prev !== null) {
if (prev.provider === provider) {
// Existing instance found.
// 已找到现有实例。
return prev;
}
const next = prev.next;
if (next === null) {
break;
}
prev = next;
}
const gesture: ScheduledGesture = {
provider: provider,
count: 0,
// 未初始化
rangeStart: 0, // Uninitialized
// 未初始化
rangeEnd: 100, // Uninitialized
types: null,
running: null,
commit: null,
committing: false,
// 未初始化而开始。
revertLane: NoLane, // Starts uninitialized.
prev: prev,
next: null,
};
if (prev === null) {
root.pendingGestures = gesture;
} else {
prev.next = gesture;
}
ensureRootIsScheduled(root);
return gesture;
}
开始计划手势
备注
getCurrentGestureOffset()由平台实现
export function startScheduledGesture(
root: FiberRoot,
gestureTimeline: GestureTimeline,
gestureOptions: ?GestureOptions,
transitionTypes: null | TransitionTypes,
): null | ScheduledGesture {
const rangeStart =
gestureOptions && gestureOptions.rangeStart != null
? gestureOptions.rangeStart
: getCurrentGestureOffset(gestureTimeline);
const rangeEnd =
gestureOptions && gestureOptions.rangeEnd != null
? gestureOptions.rangeEnd
: rangeStart < 50
? 100
: 0;
let prev = root.pendingGestures;
while (prev !== null) {
if (prev.provider === gestureTimeline) {
// Existing instance found.
// 已找到现有实例。
prev.count++;
// Update the options.
// 更新选项。
prev.rangeStart = rangeStart;
prev.rangeEnd = rangeEnd;
if (transitionTypes !== null) {
let scheduledTypes = prev.types;
if (scheduledTypes === null) {
scheduledTypes = prev.types = [];
}
for (let i = 0; i < transitionTypes.length; i++) {
const transitionType = transitionTypes[i];
if (scheduledTypes.indexOf(transitionType) === -1) {
scheduledTypes.push(transitionType);
}
}
}
return prev;
}
const next = prev.next;
if (next === null) {
break;
}
prev = next;
}
// No scheduled gestures. It must mean nothing for this renderer updated but
// some other renderer might have updated.
//
// 没有计划中的手势。这一定不意味着此渲染器已更新,
// 但其他渲染器可能已更新。
return null;
}
取消计划手势
备注
getCurrentGestureOffset由 ReactFiberConfig#getCurrentGestureOffset 实现includesBlockingLane()由 [ReactFiberLane#includesBlockingLane] 实现includesTransitionLane()由 [ReactFiberLane#includesTransitionLane] 实现stopViewTransition()由宿主环境提供
export function cancelScheduledGesture(
root: FiberRoot,
gesture: ScheduledGesture,
): void {
// Entangle any Transitions started in this event with the revertLane of the gesture
// so that we commit them all together.
// 将在此事件中启动的任何过渡与手势的 revertLane 纠缠在一起这样我们就可以将它们一起提交。
if (gesture.revertLane !== NoLane) {
const entangledLanes = gesture.revertLane | requestTransitionLane(null);
markRootEntangled(root, entangledLanes);
}
gesture.count--;
if (gesture.count === 0) {
// If the end state is closer to the end than the beginning then we commit into the
// end state before reverting back (or applying a new Transition).
// 如果结束状态比开始更接近结束,那么我们会在回退之前提交到结束状态(或应用新的过渡)
// Otherwise we just revert back and don't commit.
// 否则,我们只会回退而不提交。
let shouldCommit: boolean;
const finalOffset = getCurrentGestureOffset(gesture.provider);
const rangeStart = gesture.rangeStart;
const rangeEnd = gesture.rangeEnd;
if (rangeStart < rangeEnd) {
shouldCommit = finalOffset > rangeStart + (rangeEnd - rangeStart) / 2;
} else {
shouldCommit = finalOffset < rangeEnd + (rangeStart - rangeEnd) / 2;
}
// TODO: If we're currently rendering this gesture, we need to restart the render
// on a different gesture or cancel the render..
// TODO: We might want to pause the View Transition at this point since you should
// no longer be able to update the position of anything but it might be better to
// just commit the gesture state.
//
// 待办事项:如果我们当前正在渲染这个手势,我们需要在不同的手势上重新开始渲染,或者取消渲染。
// 待办事项:我们可能想在这一点暂停视图过渡,因为
// 你应该不能再更新任何位置,但可能更好的是直接提交手势状态。
const runningTransition = gesture.running;
if (runningTransition !== null && shouldCommit) {
// If we are going to commit this gesture in its to state, we need to wait to
// stop it until it commits. We should now schedule a render at the gesture
// lane to actually commit it.
// 如果我们打算在其原始状态下执行这个手势,我们需要等到它完成时才停止它。我们现在应该在手势通
// 道安排一次渲染以实际提交它。
gesture.committing = true;
if (root.pendingGestures === gesture) {
const commitCallback = gesture.commit;
if (commitCallback !== null) {
gesture.commit = null;
// If we already have a commit prepared we can immediately commit the tree
// without rerendering.
// 如果我们已经准备好了一个提交,我们可以立即提交树而无需重新渲染。
// TODO: Consider scheduling this in a task instead of synchronously inside the last cancellation.s
// TODO: 考虑将其安排在一个任务中,而不是在最后一次取消内部同步执行。
commitCallback();
} else {
// Ping the root given the new state. This is similar to pingSuspendedRoot.
// 根据新的状态 ping 根节点。这类似于 pingSuspendedRoot。
pingGestureRoot(root);
}
}
} else {
// If we're not going to commit this gesture we can stop the View Transition
// right away and delete the scheduled gesture from the pending queue.
// 如果我们不打算执行这个手势,我们可以立即停止视图过渡并从待处理队列中删除已安排的手势。
if (gesture.prev === null) {
if (root.pendingGestures === gesture) {
// This was the currently rendering gesture.
// 这是当前正在渲染的手势。
root.pendingGestures = gesture.next;
let remainingLanes = root.pendingLanes;
if (root.pendingGestures === null) {
// Gestures don't clear their lanes while the gesture is still active but it
// might not be scheduled to do any more renders and so we shouldn't schedule
// any more gesture lane work until a new gesture is scheduled.
// 手势在手势仍然处于活动状态时不会清除它们的通道,但它可能没有安排进行更多的渲染,因
// 此在安排新的手势之前,我们不应安排更多的手势通道工作。
remainingLanes &= ~GestureLane;
}
markRootFinished(
root,
GestureLane,
remainingLanes,
NoLane,
NoLane,
NoLanes,
);
// If we had a currently rendering gesture we need to now reset the gesture lane to
// now render the next gesture or cancel if there's no more gestures in the queue.
// 如果我们有一个当前正在渲染的手势,我们现在需要重置手势通道,以便渲染下一个手势,或者
// 如果队列中没有更多手势则取消。
restartGestureRoot(root);
}
gesture.running = null;
if (runningTransition !== null) {
stopViewTransition(runningTransition);
}
} else {
// This was not the current gesture so it doesn't affect the current render.
// 这不是当前的手势,所以它不会影响当前的渲染。
gesture.prev.next = gesture.next;
if (gesture.next !== null) {
gesture.next.prev = gesture.prev;
}
gesture.prev = null;
gesture.next = null;
}
}
}
}
停止已完成的手势
备注
stopViewTransition由 ReactFiberConfig#stopViewTransition 实现
export function stopCommittedGesture(root: FiberRoot) {
// The top was just committed. We can delete it from the queue
// and stop its View Transition now.
// 顶部刚刚被提交。我们可以从队列中删除它并立即停止它的视图过渡。
const committedGesture = root.pendingGestures;
if (committedGesture !== null) {
// Mark it as no longer committing and should no longer be included in rerenders.
// 将其标记为不再提交,并且不应再包含在重新渲染中。
committedGesture.committing = false;
const nextGesture = committedGesture.next;
if (nextGesture === null) {
// Gestures don't clear their lanes while the gesture is still active but it
// might not be scheduled to do any more renders and so we shouldn't schedule
// any more gesture lane work until a new gesture is scheduled.
// 手势在手势仍然处于活动状态时不会清除它们的通道,但它可能没有安排进行更多的渲染,因此在安排
// 新的手势之前,我们不应安排更多的手势通道工作。
root.pendingLanes &= ~GestureLane;
} else {
nextGesture.prev = null;
}
root.pendingGestures = nextGesture;
const runningTransition = committedGesture.running;
if (runningTransition !== null) {
committedGesture.running = null;
stopViewTransition(runningTransition);
}
}
}
安排手势提交
export function scheduleGestureCommit(
gesture: ScheduledGesture,
callback: () => void,
): () => void {
gesture.commit = callback;
return function () {
gesture.commit = null;
};
}