flutter
- 快速滑动判断
Scrollable.recommendDeferredLoadingForContex - 下一帧执行
SchedulerBinding.instance.scheduleFrameCallback
ScrollAwareImageProvider
if (Scrollable.recommendDeferredLoadingForContext(context.context!)) {
SchedulerBinding.instance!.scheduleFrameCallback((_) {
scheduleMicrotask(() => resolveStreamForKey(configuration, stream, key, handleError));
});
return;
}
- 保证非空访问的BuildContext
DisposableBuildContext,需要主动创建与解除
Image
late DisposableBuildContext<State<Image>> _scrollAwareContext;
@override
void initState() {
super.initState();
_scrollAwareContext = DisposableBuildContext<State<Image>>(this);
}
@override
void dispose() {
_scrollAwareContext.dispose();
super.dispose();
}
-
dirtyElements刷新的顺序
当WidgetBinding开始处理帧刷新时,有一项任务是更新element树中脏节点(_dirtyElements:一个Element数组)。
由于Element.rebuild会刷新所有需要刷新的子节点,那么有个问题就是,如果一个节点和它之上某一层的父节点都被标记,那么这个节点会有被刷新两次的可能。
所以在代码中,先对数组进行了排序,depth浅的节点在深的之前刷新,这样就保障了子节点不会被刷新两次的风险。BuildOwner::buildScope源码
void buildScope(Element context, [ VoidCallback? callback ]) {
…
_dirtyElements.sort(Element._sort);
_dirtyElementsNeedsResorting = false;
int dirtyCount = _dirtyElements.length;
int index = 0;
…
while (index < dirtyCount) {
…
_dirtyElements[index].rebuild();
index += 1;
if (dirtyCount < _dirtyElements.length || _dirtyElementsNeedsResorting!) {
_dirtyElements.sort(Element._sort);
_dirtyElementsNeedsResorting = false;
dirtyCount = _dirtyElements.length;
while (index > 0 && _dirtyElements[index - 1].dirty) {
// It is possible for previously dirty but inactive widgets to move right in the list.
// We therefore have to move the index left in the list to account for this.
// We don't know how many could have moved. However, we do know that the only possible
// change to the list is that nodes that were previously to the left of the index have
// now moved to be to the right of the right-most cleaned node, and we do know that
// all the clean nodes were to the left of the index. So we move the index left
// until just after the right-most clean node.
index -= 1;
}
}
}
…
}