diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e7ddec..e30e2a98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Fixed [#576](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/576) - Fixed the showcase key update issue by removing the old controller entry and registering the new key. - Fixed [#578](https://github.com/SimformSolutionsPvtLtd/showcaseview/issues/578) - Fixed showcase key issue. +- Fixed [#583](https://github.com/SimformSolutionsPvtLtd/showcaseview/pull/583) - Accommodate + over scroll when auto scroll is enabled. ## [5.0.0] diff --git a/lib/src/showcase/showcase.dart b/lib/src/showcase/showcase.dart index 2acdd736..92ff3738 100644 --- a/lib/src/showcase/showcase.dart +++ b/lib/src/showcase/showcase.dart @@ -563,7 +563,7 @@ class _ShowcaseState extends State { super.didUpdateWidget(oldWidget); if (oldWidget == widget) return; _updateControllerValues(); - if(oldWidget.showcaseKey != widget.showcaseKey) { + if (oldWidget.showcaseKey != widget.showcaseKey) { ShowcaseService.instance.removeController( key: oldWidget.showcaseKey, id: _uniqueId, diff --git a/lib/src/showcase/showcase_controller.dart b/lib/src/showcase/showcase_controller.dart index c09c7101..af1ed33c 100644 --- a/lib/src/showcase/showcase_controller.dart +++ b/lib/src/showcase/showcase_controller.dart @@ -181,6 +181,8 @@ class ShowcaseController { duration: showcaseView.scrollDuration, alignment: config.scrollAlignment, ); + // For the cases when scrollAlignment causes overscroll. + await _waitForScrollToSettle(); isScrollRunning = false; setupShowcase(shouldUpdateOverlay: shouldUpdateOverlay); @@ -456,6 +458,28 @@ class ShowcaseController { scheduler.addPostFrameCallback((_) => process()); } + /// Waits until the scroll position stops changing (settles). + Future _waitForScrollToSettle({ + Duration checkInterval = const Duration(milliseconds: 60), + int maxChecks = 120, + }) async { + final scrollableState = Scrollable.maybeOf(_context); + if (scrollableState == null) return; + + final position = scrollableState.position; + var lastPixels = position.pixels; + var checks = 0; + + while (checks < maxChecks) { + await Future.delayed(checkInterval); + if (!position.hasPixels) break; + final currentPixels = position.pixels; + if ((currentPixels - lastPixels).abs() < 0.5) break; + lastPixels = currentPixels; + checks++; + } + } + @override int get hashCode => Object.hash(id, key); diff --git a/lib/src/tooltip/tooltip_content.dart b/lib/src/tooltip/tooltip_content.dart index 392e7d95..01c4e7db 100644 --- a/lib/src/tooltip/tooltip_content.dart +++ b/lib/src/tooltip/tooltip_content.dart @@ -101,8 +101,12 @@ class ToolTipContent extends StatelessWidget { if (titleWidget != null) titleWidget, if (descriptionWidget != null) descriptionWidget, if (actionWidget != null && - tooltipActionConfig.position.isInsideVertical) + tooltipActionConfig.position.isInsideVertical) ...[ + SizedBox( + height: tooltipActionConfig.gapBetweenContentAndAction, + ), actionWidget, + ], ], ); @@ -116,6 +120,7 @@ class ToolTipContent extends StatelessWidget { final gap = SizedBox( width: tooltipActionConfig.gapBetweenContentAndAction, ); + return Row( mainAxisSize: MainAxisSize.min, children: [