Skip to content

Setting Up the Autoscroll SDK

What you'll learn

  • Generating the Autoscroll SDK
  • Registering a widget location's GlobalKey during build
  • Scrolling to a registered location from anywhere in the app
  • Understanding the no-op behavior for unregistered or unmounted ids
  • Why this SDK does not support scrolling deep into virtualized lists

Prerequisites

Step 1: Generate the Autoscroll SDK

The Autoscroll SDK is a Free tier brick.

bash
archipelago generate autoscroll_sdk

There are no generation variables — the SDK is entirely string-keyed at runtime, with no fixed enum of screen names to maintain.

Step 2: Understand the Generated Structure

The Autoscroll SDK uses the API/Impl split pattern:

features/
└── autoscroll_sdk/
    ├── autoscroll_sdk_api/     # AutoscrollSdk contract — no models, no plugin
    └── autoscroll_sdk_impl/    # In-memory Map<String, GlobalKey> registry
        └── lib/src/
            ├── autoscroll_sdk_impl.dart
            └── di/             # AutoscrollSdkImplPackageModule

Features that register or scroll to a location depend only on autoscroll_sdk_api.

Step 3: Register a Widget Location

Call getOrCreateKey(id) once per build, on the widget you want to be able to scroll back to. It is safe to call on every build — repeated calls with the same id return the same key instance:

dart
// A transaction list item, keyed by its own id:
final autoscroll = getIt<AutoscrollSdk>();

ListTile(
  key: autoscroll.getOrCreateKey('transaction-$transactionId'),
  title: Text(transaction.title),
);

Step 4: Scroll to a Registered Location

From anywhere else in the app — typically a deep-link handler or a notification tap handler — call scrollTo once the owning screen is expected to already be built:

dart
final autoscroll = getIt<AutoscrollSdk>();
await autoscroll.scrollTo('transaction-42');

scrollTo accepts optional duration, curve, alignment, and alignmentPolicy parameters, all forwarded to Scrollable.ensureVisible. The defaults animate a short scroll that centers the target in the viewport:

dart
await autoscroll.scrollTo(
  'transaction-42',
  duration: const Duration(milliseconds: 500),
  curve: Curves.easeOutCubic,
  alignment: 0, // pin to the leading edge instead of centering
);

Step 5: Handle the No-op Case

scrollTo never throws. It returns false when:

  • id was never registered via getOrCreateKey, or
  • id is registered but its widget is not currently mounted (e.g. the owning screen has not been built yet, or has already been disposed).
dart
final scrolled = await autoscroll.scrollTo('transaction-42');
if (!scrolled) {
  // Fall back to a default destination, or do nothing — a bad deep link
  // should never crash the app.
  await context.router.push(const TransactionListRoute());
}

Step 6: Release Stale Registrations (Optional)

If a screen that owns a registered location is being permanently disposed and its id should not be reused stale, call release:

dart
@override
void dispose() {
  getIt<AutoscrollSdk>().release('transaction-42');
  super.dispose();
}

Call reset() to clear every registration at once — useful for tests or a full state reset (e.g. sign-out).

Understanding the Virtualized-List Limitation

scrollTo resolves the target through its GlobalKey's current BuildContext, which must already exist. This works reliably for:

  • Content currently on screen
  • Content within a lazy list's cache extent
  • Any non-lazy scrollable, such as a Column wrapped in a SingleChildScrollView

It does not support scrolling to an item far outside a virtualized list's currently-built range — there is deliberately no height-preservation cache for that case, keeping the SDK simple. Reserve registered ids for content that is realistically already laid out, such as sections of a single screen. For guaranteed reachability deep into a long ListView.builder, use a dedicated package such as scrollable_positioned_list instead.

Common Customizations

GoalWhat to do
Scroll instantly, no animationPass duration: Duration.zero
Pin the target to the top of the viewportPass alignment: 0
Pin the target to the bottom of the viewportPass alignment: 1
Clear a stale registration on screen disposalCall release(id) in dispose()
Reset all registrations (e.g. sign-out)Call reset()

Next Steps

  • Wire scrollTo into your deep-link handler alongside route navigation
  • Configure push notifications to land users on a specific transaction or section via a registered id

Built by Banua Coder