fixed scrolling after scaling

This commit is contained in:
Thibault Deckers 2020-05-04 12:43:32 +09:00
parent 6e53ce8cf3
commit 2740bdc597

View file

@ -32,6 +32,7 @@ class GridScaleGestureDetector extends StatefulWidget {
class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> { class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
double _startExtent, _extentMin, _extentMax; double _startExtent, _extentMin, _extentMax;
bool _applyingScale = false;
ValueNotifier<double> _scaledExtentNotifier; ValueNotifier<double> _scaledExtentNotifier;
OverlayEntry _overlayEntry; OverlayEntry _overlayEntry;
ThumbnailMetadata _metadata; ThumbnailMetadata _metadata;
@ -47,6 +48,10 @@ class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
// horizontal drag gestures are interpreted as scaling // horizontal drag gestures are interpreted as scaling
}, },
onScaleStart: (details) { onScaleStart: (details) {
// the gesture detector wrongly detects a new scaling gesture
// when scaling ends and we apply the new extent, so we prevent this
// until we scaled and scrolled to the tile in the new grid
if (_applyingScale) return;
final scrollableContext = widget.scrollableKey.currentContext; final scrollableContext = widget.scrollableKey.currentContext;
final RenderBox scrollableBox = scrollableContext.findRenderObject(); final RenderBox scrollableBox = scrollableContext.findRenderObject();
final result = BoxHitTestResult(); final result = BoxHitTestResult();
@ -86,12 +91,13 @@ class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
_scaledExtentNotifier.value = (_startExtent * s).clamp(_extentMin, _extentMax); _scaledExtentNotifier.value = (_startExtent * s).clamp(_extentMin, _extentMax);
}, },
onScaleEnd: (details) { onScaleEnd: (details) {
if (_scaledExtentNotifier == null) return;
if (_overlayEntry != null) { if (_overlayEntry != null) {
_overlayEntry.remove(); _overlayEntry.remove();
_overlayEntry = null; _overlayEntry = null;
} }
if (_scaledExtentNotifier == null) return;
_applyingScale = true;
final oldExtent = tileExtentNotifier.value; final oldExtent = tileExtentNotifier.value;
// sanitize and update grid layout if necessary // sanitize and update grid layout if necessary
final newExtent = TileExtentManager.applyTileExtent( final newExtent = TileExtentManager.applyTileExtent(
@ -101,23 +107,25 @@ class _GridScaleGestureDetectorState extends State<GridScaleGestureDetector> {
newExtent: _scaledExtentNotifier.value, newExtent: _scaledExtentNotifier.value,
); );
_scaledExtentNotifier = null; _scaledExtentNotifier = null;
if (newExtent == oldExtent) return; if (newExtent == oldExtent) {
_applyingScale = false;
// TODO TLAD fix scroll to specific thumbnail with custom SliverList } else {
// scroll to show the focal point thumbnail at its new position // scroll to show the focal point thumbnail at its new position
final viewportClosure = _renderViewport; final viewportClosure = _renderViewport;
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
final scrollableContext = widget.scrollableKey.currentContext; // about scrolling & offset retrieval:
final gridSize = (scrollableContext.findRenderObject() as RenderBox).size; // `Scrollable.ensureVisible` only works on already rendered objects
final sectionLayout = Provider.of<SectionedListLayout>(context, listen: false); // `RenderViewport.showOnScreen` can find any `RenderSliver`, but not always a `RenderMetadata`
final tileRect = sectionLayout.getTileRect(_metadata.entry); // `RenderViewport.scrollOffsetOf` is a good alternative
final scrollOffset = (tileRect?.top ?? 0) - gridSize.height / 2; final scrollableContext = widget.scrollableKey.currentContext;
viewportClosure.offset.jumpTo(scrollOffset.clamp(.0, double.infinity)); final gridSize = (scrollableContext.findRenderObject() as RenderBox).size;
// about scrolling & offset retrieval: final sectionLayout = Provider.of<SectionedListLayout>(context, listen: false);
// `Scrollable.ensureVisible` only works on already rendered objects final tileRect = sectionLayout.getTileRect(_metadata.entry);
// `RenderViewport.showOnScreen` can find any `RenderSliver`, but not always a `RenderMetadata` final scrollOffset = (tileRect?.top ?? 0) - gridSize.height / 2;
// `RenderViewport.scrollOffsetOf` is a good alternative viewportClosure.offset.jumpTo(max(.0, scrollOffset));
}); _applyingScale = false;
});
}
}, },
child: widget.child, child: widget.child,
); );