add caching to widgetsWithScreenPositions()
This commit is contained in:
@@ -30,6 +30,11 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
bool _firstBuild = true;
|
bool _firstBuild = true;
|
||||||
int? _focusChildOnInit; // if set, will focus on this child on first build
|
int? _focusChildOnInit; // if set, will focus on this child on first build
|
||||||
CanvasBackground background;
|
CanvasBackground background;
|
||||||
|
// these are used to cache result of widgetsWithScreenPositions
|
||||||
|
List<ChildInfo> _lastRenderedWidgets = [];
|
||||||
|
Offset? _lastProcessedOffset;
|
||||||
|
double? _lastProcessedScale;
|
||||||
|
bool _markDirty = false; // do any of the non scale or offset changes require a rebuild?
|
||||||
|
|
||||||
bool debug;
|
bool debug;
|
||||||
final Duration defaultAnimationDuration;
|
final Duration defaultAnimationDuration;
|
||||||
@@ -54,6 +59,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
Size get canvasSize => _canvasSize;
|
Size get canvasSize => _canvasSize;
|
||||||
Offset get _ssCenter => Offset(_canvasSize.width / 2, _canvasSize.height / 2);
|
Offset get _ssCenter => Offset(_canvasSize.width / 2, _canvasSize.height / 2);
|
||||||
Offset get _gsCenter => ssToGs(_ssCenter, _gsTopLeftOffset, _scale);
|
Offset get _gsCenter => ssToGs(_ssCenter, _gsTopLeftOffset, _scale);
|
||||||
|
bool get _renderCacheDirty => _lastProcessedOffset != _gsTopLeftOffset || _lastProcessedScale != _scale || _markDirty;
|
||||||
|
|
||||||
// ==================== Callback Functions ====================
|
// ==================== Callback Functions ====================
|
||||||
|
|
||||||
@@ -68,7 +74,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
// if the first init, re-render as I don't have the canvas size to build widgets
|
// if the first init, re-render as I don't have the canvas size to build widgets
|
||||||
if (!_init) {
|
if (!_init) {
|
||||||
_init = true;
|
_init = true;
|
||||||
Future.microtask(notifyListeners);
|
Future.microtask(markDirty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,6 +92,17 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== Utils ====================
|
||||||
|
|
||||||
|
void markDirty() {
|
||||||
|
_markDirty = true;
|
||||||
|
// this is done instead of just notifyListeners() so as to differentiate
|
||||||
|
// betweena adhoc calls to widgetsWithScreenPositions
|
||||||
|
// if you need to call notifyListeners() from within this class,
|
||||||
|
// it should always be with markDirty()
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== Child Management ====================
|
// ==================== Child Management ====================
|
||||||
|
|
||||||
/// Add a child at a given position with a widget. Returns the child ID.
|
/// Add a child at a given position with a widget. Returns the child ID.
|
||||||
@@ -101,7 +118,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
_children[_nextId] = _ChildInfo(gsPosition: position, widget: widget, lastRenderedSize: childSize);
|
_children[_nextId] = _ChildInfo(gsPosition: position, widget: widget, lastRenderedSize: childSize);
|
||||||
_spatialHash.add(position.toPoint(), _nextId); // add to spatial hash
|
_spatialHash.add(position.toPoint(), _nextId); // add to spatial hash
|
||||||
notifyListeners();
|
markDirty();
|
||||||
return _nextId++;
|
return _nextId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +129,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
_spatialHash.remove(_children[id]!.gsPosition.toPoint());
|
_spatialHash.remove(_children[id]!.gsPosition.toPoint());
|
||||||
_children.remove(id);
|
_children.remove(id);
|
||||||
notifyListeners();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove all children. Does not change where you are on the canvas.
|
/// Remove all children. Does not change where you are on the canvas.
|
||||||
@@ -120,14 +137,14 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
_children.clear();
|
_children.clear();
|
||||||
_spatialHash.clear();
|
_spatialHash.clear();
|
||||||
_nextId = 0;
|
_nextId = 0;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the position of a child by its ID.
|
/// Update the position of a child by its ID.
|
||||||
int updatePosition(int id, Offset newPosition) {
|
int updatePosition(int id, Offset newPosition) {
|
||||||
if (_children.containsKey(id)) {
|
if (_children.containsKey(id)) {
|
||||||
_children[id]!.gsPosition = newPosition;
|
_children[id]!.gsPosition = newPosition;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
return id;
|
return id;
|
||||||
} else {
|
} else {
|
||||||
throw _ChildNotFoundException;
|
throw _ChildNotFoundException;
|
||||||
@@ -141,7 +158,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
// Create a new _ChildInfo with the new widget
|
// Create a new _ChildInfo with the new widget
|
||||||
_children[id] = _ChildInfo(gsPosition: child.gsPosition, widget: newWidget)
|
_children[id] = _ChildInfo(gsPosition: child.gsPosition, widget: newWidget)
|
||||||
..lastRenderedSize = child.lastRenderedSize;
|
..lastRenderedSize = child.lastRenderedSize;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
} else {
|
} else {
|
||||||
throw _ChildNotFoundException;
|
throw _ChildNotFoundException;
|
||||||
}
|
}
|
||||||
@@ -183,7 +200,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
_gsTopLeftOffset -= details.focalPointDelta / _scale;
|
_gsTopLeftOffset -= details.focalPointDelta / _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyListeners();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increment or decrement the scale by an additive delta value.
|
/// Increment or decrement the scale by an additive delta value.
|
||||||
@@ -192,7 +209,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
final newScale = _scale + delta;
|
final newScale = _scale + delta;
|
||||||
_gsTopLeftOffset = newGsTopLeftOnScaling(_gsTopLeftOffset, focalPoint, _scale, newScale);
|
_gsTopLeftOffset = newGsTopLeftOnScaling(_gsTopLeftOffset, focalPoint, _scale, newScale);
|
||||||
_scale = newScale;
|
_scale = newScale;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Positioning Logic ====================
|
// ==================== Positioning Logic ====================
|
||||||
@@ -207,9 +224,18 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
_firstBuild = false;
|
_firstBuild = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_renderCacheDirty && !forceRebuild) {
|
||||||
|
// if the render cache is not dirty, we can use the cached result
|
||||||
|
return _lastRenderedWidgets;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastProcessedOffset = _gsTopLeftOffset;
|
||||||
|
_lastProcessedScale = _scale;
|
||||||
|
_markDirty = false;
|
||||||
|
|
||||||
final idsToBuild = _childrenWithinBuildArea(_gsCenter, _buildExtent);
|
final idsToBuild = _childrenWithinBuildArea(_gsCenter, _buildExtent);
|
||||||
|
|
||||||
return idsToBuild.map((id) {
|
return _lastRenderedWidgets = idsToBuild.map((id) {
|
||||||
final item = _children[id]!;
|
final item = _children[id]!;
|
||||||
final ssPosition = gsToSs(item.gsPosition, _gsTopLeftOffset, _scale);
|
final ssPosition = gsToSs(item.gsPosition, _gsTopLeftOffset, _scale);
|
||||||
var child = item.widget;
|
var child = item.widget;
|
||||||
@@ -239,7 +265,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
animateToOffsetAndScale(offset: newGsTopLeft, duration: duration, scale: _scale);
|
animateToOffsetAndScale(offset: newGsTopLeft, duration: duration, scale: _scale);
|
||||||
} else {
|
} else {
|
||||||
_gsTopLeftOffset = newGsTopLeft;
|
_gsTopLeftOffset = newGsTopLeft;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +325,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
} else {
|
} else {
|
||||||
_gsTopLeftOffset = newGsTopLeft;
|
_gsTopLeftOffset = newGsTopLeft;
|
||||||
_scale = newScale;
|
_scale = newScale;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +348,7 @@ class LazyCanvasController with ChangeNotifier {
|
|||||||
anim.addListener(() {
|
anim.addListener(() {
|
||||||
_gsTopLeftOffset = offsetAnimation.value;
|
_gsTopLeftOffset = offsetAnimation.value;
|
||||||
_scale = scaleAnimation.value;
|
_scale = scaleAnimation.value;
|
||||||
notifyListeners();
|
markDirty();
|
||||||
});
|
});
|
||||||
|
|
||||||
await anim.forward();
|
await anim.forward();
|
||||||
|
|||||||
Reference in New Issue
Block a user