showcase_tutorial 1.15.1
showcase_tutorial: ^1.15.1 copied to clipboard
A Flutter package to Showcase/Highlight widgets step by step.
Changelog #
1.15.1 #
Performance and layout fixes. Nothing to change in your code.
- Lighter tours. A
Showcasethat isn't currently showing no longer adds anything to your widget tree. A 60-step tour now builds 120 fewer widgets than before, and advancing a step does less work. Tours with many steps benefit the most. - Fixed: a step using
tooltipPosition: TooltipPosition.leftor.righttogether with action buttons could draw its tooltip off the top of the screen when the highlighted widget was near the top edge. It now stays beside its target, where you asked for it. - Fixed: action buttons placed outside the tooltip could be drawn under the
status bar and cut off, again for a widget near the top of the screen. They
are kept on screen now. If you position them yourself with
Showcase.actionButtonsPosition, your values are used exactly as before. - Tip: if you show buttons on every step with
ShowCaseWidget.globalActions, preferTooltipActionPosition.inside. Theoutsideplacement has little room to work with when a target sits near a screen edge.
1.15.0 #
New action-button options, a fix, and a speed-up. Everything is additive — existing tours behave exactly as before.
New #
-
Set the tooltip's buttons once for the whole tour. Instead of repeating
actions:on everyShowcase, declare them onShowCaseWidget:ShowCaseWidget( globalActions: (context) => const ShowCaseDefaultActions(), globalActionSettings: const ActionsSettings(containerHeight: 40), hideActionsForShowcase: [_lastStep], // steps that shouldn't show them builder: Builder(builder: (context) => const HomePage()), );A per-step
Showcase.actionsstill wins. Styling (globalActionSettings) and placement (globalActionButtonsPosition) fall back separately, so a step can change just its buttons and keep the tour's look. -
Buttons inside the tooltip.
TooltipActionPosition.insidedraws them within the tooltip, below the description, with the tooltip growing to fit. Set it tour-wide withShowCaseWidget.actionsPositionor per step withShowcase.actionsPosition. The default staysoutside, which positions them separately from the tooltip as before. Give inside buttons more room withActionsSettings.containerHeightif 40px isn't enough. -
ShowCaseWidget.activeTargetWidgetnow takes an optionalaspect. Pass a step'sGlobalKeyto have your widget rebuild only when that step becomes active or inactive. Omit it for the previous behaviour.
Fixed #
enableShowcasenow works at runtime. Setting it tofalsewhile a tour was running used to leave the overlay on screen. It now ends the tour: the step that was showing gets itsonDismiss, andShowCaseWidget.onDismissreports where the user was left. Turning it back on does not resume the tour — callstartShowCaseagain.
Faster #
- Advancing a step no longer rebuilds every
Showcaseon screen, only the step being left and the one being entered. In a 60-step tour that is 125 widget rebuilds per "next" instead of 299, and the number no longer grows with the length of the tour. This frees up work on the UI thread; it does not change how the tour looks or how fast it animates.
1.14.1 #
A performance pass over the showcase overlay. No API changes — every item below is internal, and behaviour is unchanged.
- PERF: an idle
Showcaseno longer mounts an overlay entry. EveryShowcaseused to insert its ownOverlayEntryas soon as it was built and keep it for the life of the route, so a screen with 30 steps carried 30 entries — each rebuilt on every ancestor rebuild only to return an empty box. Only the step that is actually showing mounts one now, and it is removed when the tour moves on. - PERF: the target snapshot is captured once per step instead of once per
rebuild.
highlightExactShapeand multi-widget (keys) steps used aFutureBuilderwhose future was created insidebuild, so every rebuild re-ranRenderRepaintBoundary.toImagefollowed by a full PNG encode and decode — several times a second while the tooltip animates — and leaked everyui.Imageit produced. The capture now happens once when the step opens, the PNG round trip is gone (the image is painted directly), and the images are disposed when the step closes. The snapshot's position is still re-read each build, so it keeps tracking a target that scrolls. - PERF: the target's geometry is measured once per frame. Laying out a tooltip asks for the target's center, top, bottom and height dozens of times, and each ask used to walk the render tree again. A single measurement is now shared for the frame — roughly 23x fewer render-tree walks per rebuild in a 20-step tour.
- PERF: the tour's state is resolved once per overlay build. Building the
overlay read ~20 values off
ShowCaseWidget.of(context), and each one was a freshfindAncestorStateOfTypewalk to the top of the element tree. - PERF: no more
LayoutBuilderaround every showcased widget. It added a render object perShowcaseand rebuilt the widget's whole subtree during layout on any constraint change (rotation, keyboard, window resize), while its constraints were never used. - PERF: the tooltip is painted on its own layer, so the looping "moving"
animation translates a cached layer instead of re-rasterising the tooltip's
text, arrow and background every frame; the dimmed scrim is a plain
ColoredBoxrather than a decoratedContainer; and theTextPainterused to measure tooltip text is disposed instead of leaking its native paragraph.
1.14.0 #
- FEAT: dynamic callback registration — register step listeners on the
controller at runtime with
addOnStartCallback/removeOnStartCallbackandaddOnCompleteCallback/removeOnCompleteCallback. UnlikeShowCaseWidget.onStart/onComplete, which are fixed when theShowCaseWidgetis built, these let a screen, controller, or analytics service deeper in the tree observe the tour for as long as it lives (register ininitState, remove indispose). Listeners run in addition to the widget-level callbacks, in registration order, and receive the same(int? index, GlobalKey key)— now typed asShowcaseStepCallback. Removing a listener while it is being dispatched is safe. - FEAT:
Showcase.onTargetRectUpdate— called with the highlighted target's bounds (aRectin global coordinates) whenever they change while the step is active: after a scroll, a rotation, the keyboard opening, or the target resizing. Fires once with the initial bounds when the step becomes active and is delivered after layout, so it is safe tosetStatefrom it. Useful for anchoring your own UI — e.g. afloatingActionWidgetthat should follow just below the highlight. The rect describes the target itself;targetPaddingis not included. Defaults tonull. - FEAT:
ShowCaseWidget.of(context).isTargetRendered(key)— controller helper that reports whether a step's target is currently mounted and laid out, replacing manualkey.currentContext != nullchecks (which are alsotruefor a mounted but not-yet-laid-out widget). Handy beforegoToKey/startShowCaseon steps whose targets render conditionally. - FEAT: per-step barrier override —
Showcase.barrierInteractionoverrides the tour-wideShowCaseWidget.barrierInteractionfor a single step, so one step can make the background inert (BarrierInteraction.none) while the rest of the tour advances on a background tap. Takes precedence over the tour-wide value, including the legacydisableBarrierInteractionflag;onBarrierClickstill fires on every barrier tap. Additive and backward-compatible — defaults tonull(use the tour-wide behaviour). - FEAT: pointer cursor on hover (web / desktop) — hovering a part of the
showcase that reacts to a click now shows
SystemMouseCursors.clickinstead of the plain arrow, so a tour reads as interactive on web and desktop. It applies to the highlighted target, a tooltip that hasonToolTipClickordisposeOnTap, and the built-in "Skip" button. A tooltip that does nothing on tap deliberately keeps the default cursor, so the pointer never promises a click that isn't there. The buttons inShowCaseDefaultActionsare Material buttons and already behaved this way. No-op on mobile (no pointer). - FEAT:
ShowCaseWidget.enablePointerCursor— tour-wide switch for the above, defaulting totrue(matchingenableKeyboardNavigationandenableAutoAnnouncements, the package's other on-by-default polish flags). Set it tofalseto keep the previous cursor behaviour everywhere. - FEAT:
Showcase.targetMouseCursor/Showcase.tooltipMouseCursor— per-step overrides of the resolved cursor, e.g.SystemMouseCursors.forbiddenon a "look, don't touch" step orMouseCursor.deferto leave one step alone. An explicit value wins even whenenablePointerCursorisfalse. Both default tonull(resolve automatically). - The target's hover region is not opaque, so the real widget underneath still receives hover events and keeps its own hover states while the showcase cursor applies.
- FEAT: animated step transitions — the highlight cut-out now glides from the
previous step's target to the next one when the tour advances, instead of
cutting there instantly. The optional highlight border and the pulse ring
follow the moving cut-out; the tooltip keeps its existing scale transition and
appears at the new target. Opt in tour-wide with
ShowCaseWidget.enableStepTransition(defaultfalse, so nothing changes for existing tours), and tune it withstepTransitionDuration(default 300 ms) andstepTransitionCurve(defaultCurves.easeInOut).- Applies to every forward and backward move —
next,previous,goTo,goToKey, a branch, a barrier tap, autoplay. The first step of a tour has nothing to glide from, so it simply appears. - Honors the platform "reduce motion" accessibility setting by jumping straight to the target, like the pulsing ring already does.
- No-op for a
highlightExactShapestep, which paints a snapshot of the target rather than a cut-out.
- Applies to every forward and backward move —
- FEAT:
ShowCaseWidget.of(context).previousTargetRect— the global bounds of the step the tour just left (nullwhile the tour is starting or once it ends). This is what drives the glide, and it is only recorded whileenableStepTransitionis on. - No shared-overlay rewrite was needed: every step already paints its own full-screen scrim, so the scrim is continuous across a step change and only the cut-out moves. The step being entered animates its own cut-out from where the previous target was, and the step being left simply stops painting.
1.13.0 #
- FEAT: floating action widget — pin a screen-anchored control (e.g. a fixed
Skip / Next button or a progress chip) above the overlay so it stays put while
the tour runs, instead of moving with each tooltip. Set one tour-wide with
ShowCaseWidget.globalFloatingActionWidget(aWidgetBuilder, so it can read the tour viaShowCaseWidget.of(context)), override it per step withShowcase.floatingActionWidget, and suppress the global one on specific steps withShowCaseWidget.hideFloatingActionWidgetForShowcase. You position the widget yourself (e.g. withAlign/Positioned); it is painted above the tooltip and receives taps. Additive and backward-compatible (defaultsnull/ empty). - FEAT: per-step
autoPlayDelay—Showcase.autoPlayDelayoverrides the tour-wideShowCaseWidget.autoPlayDelayfor a single step, so one step can linger longer (or advance quicker) than the rest during auto-play. Defaults tonull(use the tour-wide delay). As part of this, the auto-play delay now uses the fullDurationinstead of being truncated to whole seconds. - FEAT:
targetTooltipGap—Showcase.targetTooltipGapadds extra space (in logical pixels) between the target and its tooltip, on top of the default offset. It applies to every tooltip position (top / bottom / left / right). Additive and backward-compatible — defaults to0, which keeps the original spacing. - FEAT:
toolTipMargin—Showcase.toolTipMargin(anEdgeInsets, defaultEdgeInsets.all(20)) sets the minimum margin kept between the tooltip and the screen edges: the tooltip is clamped to stay at least this far from each edge, and its width/height are capped to fit within the margins. Useful to leave room for a status bar, notch, or your own fixed UI. Completes the tooltip-spacing pair withtargetTooltipGap. Backward-compatible — the default reproduces the previous edge spacing for ordinary tooltips. Also applies to the customShowcase.withWidgetcontainer, which is now clamped within the same margins. - FEAT:
scrollAlignment— control where an auto-scrolled target lands in the viewport.ShowCaseWidget.scrollAlignment(adouble, default0.5) sets it tour-wide andShowcase.scrollAlignmentoverrides it per step:0.0rests the target at the leading edge (top / left),0.5centers it,1.0rests it at the trailing edge (bottom / right). Forwarded toScrollable.ensureVisiblewhenShowCaseWidget.enableAutoScrollbrings an off-screen target into view. Additive and backward-compatible — the default0.5reproduces the previous centered behavior. - CHORE: the example app's "Feature demos" page now demonstrates the floating
action widget (a pinned "End tour" button, hidden on the last step), per-step
autoPlayDelay(an "Auto-play" toggle where the star step lingers longer), a "Wide tooltip gap" toggle fortargetTooltipGapon the center step, and a "Wide tooltip margin" toggle that pushes the edge-hugging "R" step's tooltip further in from the screen edge. - CHORE: the example app adds an "Auto-scroll alignment" demo page (reachable from
the "Feature demos" screen) where three far-apart targets in a scroll view each
land at a different spot — leading edge, center, trailing edge — via per-step
scrollAlignment.
1.12.0 #
- FEAT:
onBarrierClick— a newShowCaseWidget.onBarrierClickcallback fires whenever the dimmed background (barrier) is tapped, in addition to the configuredbarrierInteraction. It runs even whenbarrierInteractionisBarrierInteraction.none, so you can react to "the user tapped outside the highlight" (a hint nudge, a sound, analytics) without changing what the tap does; with.next/.dismissit runs first, then the configured action follows. Additive and backward-compatible (defaultnull).
1.11.0 #
- FEAT: tour-level
onDismiss— a newShowCaseWidget.onDismiss(GlobalKey? dismissedAt)callback fires whenever a tour is closed early (a barrier tap withBarrierInteraction.dismiss, theEsckey, the built-in skip button, adisposeOnTaptap, or a manualdismiss()), and reports theGlobalKeyof the step the user left off on. It is not called when the tour finishes normally by advancing past the last step —onFinishstill covers that, and exactly one of the two runs per tour. Handy for measuring onboarding drop-off. Additive and backward-compatible; distinct from the per-stepShowcase.onDismiss.
1.10.1 #
- DOCS: rewrote the README as standalone documentation — added a table of
contents, a fuller API reference (controller methods and getters, complete
ShowCaseWidgetandShowcase/Showcase.withWidgetproperty tables).
1.10.0 #
- FEAT: conditional / branching tours — a new
ShowCaseWidget.onResolveNextStepcallback lets a step decide the next step at runtime, so a tour can skip ahead or branch based on app state (e.g. "if the user already has items, jump to the checkout step"). It's consulted on every forward path (the Next button, a tap, the barrier, the keyboard, auto-play, andnext()); return theGlobalKeyof the step to jump to, ornullto advance normally. Backward and forward jumps are both allowed, and a branch is treated as an explicit jump (likegoTo).previous(),goTo(), andgoToKey()are unaffected. Additive and backward-compatible — the default isnull(no branching).
1.9.0 #
- FEAT: numeric progress indicator —
ShowCaseWidget.progressStylechooses how the built-in step indicator looks whenshowProgressis on:ShowcaseProgressStyle.dots(one dot per step, the existing default) orShowcaseProgressStyle.numeric(a compact1/6counter, handy for long tours). Additive and backward-compatible — the default is unchanged.
1.8.0 #
- FEAT: tooltip & highlight styling — finer visual control for the default
tooltip without a custom
container. New per-Showcaseoptions (each also settable tour-wide viaShowcaseStyle):arrowColor,arrowWidth,arrowHeightfor the tooltip arrow, andhighlightBorderColor/highlightBorderWidthto draw a colored border around the highlighted target. All additive and opt-in; the border follows the highlight shape and works alongsidehighlightExactShape. (Per-step overlay color is already supported viaShowcase.overlayColor.)
1.7.0 #
- FEAT: pulsing highlight ring — opt in per step with
Showcase(enablePulseAnimation: true)to draw an animated ring that pings outward around the highlight, drawing the eye to the target. Tune it withpulseColor(also settable tour-wide viaShowcaseStyle.pulseColor) andpulseDuration. Additive and off by default; the ring follows the highlight shape, works alongsidehighlightExactShape, and falls back to a single static ring when the platform "reduce motion" setting is on.
1.6.2 #
- DOCS: full dartdoc coverage of the public API — every exported class, field,
enum value, and method now has a
///comment — plus a fix for a few stale doc references. Improves the pub.flutter-io.cn documentation score and the docs tab. - DOCS: add an "Upgrading (1.4 → 1.6)" section to the README summarising what landed across those releases and how to opt in (all additive, no code changes).
- DOCS: tidy the README markdown-lint warnings (aligned the property-table pipes and fixed the ordered-list prefix in the Installing section).
- CHORE: losslessly optimise the preview GIFs with
gifsicle -O3—demo.gif4.6 MB → 0.4 MB andshowcase_tutorial.gif2.6 MB → 0.5 MB (pixel-identical) — and shipdemo.gifas a second pub.flutter-io.cn screenshot. - CHORE: add a
.pubignorethat excludes the example app's native scaffolding, the maintainer publish script, and internal docs from the published archive, dropping the package download from ~7 MB to ~0.9 MB.
1.6.1 #
- DOCS: fix the README preview GIFs.
1.6.0 #
- FEAT: built-in progress indicator and skip button in the default
tooltip, via
ShowCaseWidget.showProgressandShowCaseWidget.showSkip(label customizable withskipButtonText). The progress shows one dot per step with the active step highlighted; the skip button dismisses the whole tour. Both default tofalseand only affect the default tooltip — customcontainertooltips are untouched.
1.5.1 #
- DOCS: add a second example page ("Feature demos"), reachable from a button on
the original mail demo, that walks through the newer features (left/right
tooltip positions, progress indicator, multi-widget highlight, custom action
text,
highlightExactShape,onShow/onDismiss,barrierInteraction, auto-skip). Add a feature-walkthrough GIF to the README preview and complete the README's feature list. No library changes.
1.5.0 #
- FEAT: keyboard navigation (
ShowCaseWidget.enableKeyboardNavigation, defaulttrue) — drive the active step with a hardware keyboard:Escdismisses,→/↓/Entergo to the next step,←/↑go back. Focus-scoped, so it only acts while the overlay holds focus (never hijacks app-wide keys). Relevant on web/desktop, harmless on mobile. - FEAT: screen-reader announcements (
ShowCaseWidget.enableAutoAnnouncements, defaulttrue) — each step's title and description are announced to TalkBack/VoiceOver as it becomes active.Showcase.semanticLabeloverrides the announced text (useful for custom-containertooltips). - FIX:
Showcase.onShow/onDismiss(added in 1.4.0) could throw "setState() called during build" when the callback calledsetState(e.g. to update a "Step x of y" indicator), which cascaded into "GlobalKey used multiple times" errors. The callbacks are now dispatched after the frame.
1.4.0 #
- FEAT:
TooltipPosition.leftand.right— place the default tooltip to the side of the target, with a horizontal arrow. - FEAT: progress + navigation API on
ShowCaseWidget.of(context):currentIndex,totalSteps,isShowcaseRunning,goTo(index)andgoToKey(key)(build "Step 2 of 5" indicators and skip-to controls). - FEAT:
ShowCaseWidget.autoSkipUnmountedSteps— skip steps whose target widget isn't currently in the tree instead of showing an empty overlay. - FEAT: RTL support — the tooltip inherits the app's text direction and measures/lays out RTL text correctly.
- FEAT:
Showcase.highlightExactShape— highlight the target by its actual painted shape (a star, a pill, an icon, an irregular logo) instead of a geometrictargetShapeBorder. The target is captured as a snapshot and drawn above the dimmed overlay, so any shape is hugged exactly with no need to settargetShapeBorder/targetBorderRadiusto match it. - FEAT: per-step lifecycle callbacks
Showcase.onShowandShowcase.onDismiss— fired when a step becomes the active showcase and when it stops being active (advanced past, navigated away, or the tour is dismissed). Handy for analytics. - FEAT:
ShowCaseWidget.barrierInteraction(BarrierInteraction.next/.dismiss/.none) — choose whether tapping the dimmed background advances to the next step (default), dismisses the whole tour, or does nothing. The legacydisableBarrierInteraction: truestill works and maps to.none.
1.3.0 #
- FEAT: "show once" support for onboarding tours.
ShowCaseWidgetgains ashowcaseIdand anonShouldStartShowcaseguard (sync or async).startShowCaseconsults the guard and starts only when it returnstrue, so a tour can be shown a single time. PassstartShowCase(..., force: true)to replay (e.g. a "show tutorial again" button). The package stays storage-agnostic — persist completion yourself inonFinish.
1.2.1 #
- DOCS: rewrite the README with a Features overview and runnable examples for
every feature (custom tooltips, action buttons, multi-widget steps,
ShowcaseStyle, auto-play, programmatic control, target interactions, blur, tooltip position, enable/disable). Correct the property tables and remove the stale pre-1.0.0 migration guide.
1.2.0 #
- FEAT: add
ShowCaseWidget(style: ShowcaseStyle(...))to set default tooltip styling (tooltipBackgroundColor,textColor,titleTextStyle,descTextStyle,tooltipBorderRadius) once for everyShowcasein the tree. An individualShowcasestill overrides any value it sets. - FEAT:
Showcase.descriptionis now optional. A showcase can show just a title (or a customcontainer) without passingdescription: null. - BREAKING (minor):
Showcase.tooltipBackgroundColorandShowcase.textColorare now nullable (Color?) so they can fall back toShowcaseStyle. Code that passes these as named arguments is unaffected; only code that read the fields expecting a non-nullColorneeds a null check. - FIX: the overlay barrier was being painted twice, so the default
(non-blurred) overlay rendered at roughly double the configured opacity.
It is now drawn once at the requested
overlayColor/overlayOpacity. - FIX:
ActionsSettings.containerColoris now honoured for tooltip action buttons. Previously the action container used a hardcoded background (Colors.white/Colors.lightBlueAccent) and ignored the setting. - FIX: guard
GetPosition.getRect()against a null/unsized render object so it returnsRect.zeroinstead of throwing during teardown. - FIX: multi-widget showcases (
Showcase(keys: ...)) now skip an individual missing/unmounted widget instead of dropping every highlight for the step. - PERF:
MeasureSizenow reads its size during layout via aRenderProxyBoxinstead of scheduling a post-frame measurement on every build, and the overlay no longer schedules a rebuild callback while no showcase is active. - DOCS: document the multi-widget
keysparameter. - CHORE: correct the
flutterSDK constraint (>=3.27.0, required byColor.withValues) and addtopicsandscreenshotsto the pubspec.
1.1.2 #
- FIX: guard
_scrollIntoViewagainst a use-after-dispose crash. AShowcasedisposed within a frame of its first build (for example, a redirect right after the first build) no longer throws "Null check operator used on a null value" from its post-frame callback. - CHORE: upgrade
flutter_lintsto^6.0.0and resolve the newly surfaced lints.
1.1.1 #
- Example app: add an
isImportantfield to the mail model and refine theMailTileand detail screen styling. - Docs: fix the GitHub stars link in the README.
1.1.0 #
- FEAT: update dependency constraints to Dart SDK 3.9.0.
- Refactor the code structure for improved readability and maintainability.
- Fix minor bugs and improve performance.
- Update the documentation for new features.
1.0.4 #
- Update Flutter to 3.16.0.
1.0.0 #
- Initial release (14 Sep 2023).
