flutter_path_layout 0.1.2 copy "flutter_path_layout: ^0.1.2" to clipboard
flutter_path_layout: ^0.1.2 copied to clipboard

Reusable Flutter layouts for learning, activity, roadmap, and progression paths.

flutter_path_layout #

A reusable Flutter layout component for creating learning paths, progression paths, activity paths, onboarding paths, game maps, roadmaps, and reward paths.

The package is intentionally generic. It handles layout, scrolling, path geometry, optional connectors, and responsive positioning. The consuming app supplies every node widget, including colors, icons, semantics, gestures, and state.

Preview #

Vertical wave path Mixed node sizes path Key-based progress path

Basic Usage #

Add the package to a consuming Flutter app:

flutter pub add flutter_path_layout

For local monorepo development, use a path dependency instead:

dependencies:
  flutter_path_layout:
    path: ../../packages/flutter_path_layout

Then import the public barrel:

import 'package:flutter_path_layout/flutter_path_layout.dart';
FlutterPathLayout<Activity>(
  items: activities,
  direction: Axis.vertical,
  shape: PathShape.wave,
  itemSpacing: 120,
  amplitude: 0.3,
  itemBuilder: (context, activity, index) {
    return ActivityButton(activity: activity);
  },
)

Horizontal Usage #

FlutterPathLayout<Activity>(
  items: activities,
  direction: Axis.horizontal,
  shape: PathShape.wave,
  physics: const BouncingScrollPhysics(),
  itemBuilder: (context, activity, index) {
    return ActivityButton(activity: activity);
  },
)

Configuration #

Common options can be passed directly to FlutterPathLayout:

FlutterPathLayout<Activity>(
  items: activities,
  direction: Axis.vertical,
  shape: PathShape.zigzag,
  itemSpacing: 112,
  amplitude: 0.75,
  padding: const EdgeInsets.all(24),
  connectorStyle: const PathConnectorStyle.solid(curved: true),
  controller: scrollController,
  physics: const BouncingScrollPhysics(),
  itemBuilder: (context, activity, index) => ActivityNode(activity),
)

For repeated setups, use PathLayoutConfig:

FlutterPathLayout<Activity>(
  items: activities,
  config: const PathLayoutConfig(
    direction: Axis.vertical,
    shape: PathShape.wave,
    itemSpacing: 120,
    amplitude: 0.45,
  ),
  itemBuilder: (context, activity, index) => ActivityNode(activity),
)

Custom Node Styles #

Nodes are normal Flutter widgets. They can use GestureDetector, InkWell, Semantics, FocusableActionDetector, animations, images, or any other app composition.

FlutterPathLayout<String>(
  items: const ['lesson', 'reward', 'review'],
  itemBuilder: (context, item, index) {
    return Semantics(
      label: item,
      button: true,
      child: SizedBox.square(
        dimension: item == 'reward' ? 96 : 64,
        child: Center(child: Text(item)),
      ),
    );
  },
)

Custom Strategy #

Built-in shapes include straight, wave, zigzag, and alternating. For arbitrary patterns, pass a strategy:

FlutterPathLayout<int>(
  items: List.generate(8, (index) => index),
  strategy: CustomPathStrategy(
    positionBuilder: (context) {
      final middle = (context.itemCount - 1) / 2;
      final distance = (context.index - middle).abs() / middle;
      return (1 - distance) * 0.8;
    },
  ),
  itemBuilder: (context, item, index) => LessonNode(index: index),
)

Wave paths can be tuned with amplitude, frequency, and phase:

FlutterPathLayout<int>(
  items: items,
  shape: PathShape.wave,
  amplitude: 0.65,
  frequency: 1.5,
  phase: 0.4,
  itemBuilder: (context, item, index) => Node(index),
)

Strategies return normalized cross-axis values:

  • -1.0: far left for vertical paths, or top for horizontal paths.
  • 0.0: center.
  • 1.0: far right for vertical paths, or bottom for horizontal paths.

The layout engine clamps positions so nodes stay inside the available cross-axis area as much as the parent constraints allow.

Connector Customization #

Connectors are optional and use the same calculated geometry as node positioning.

FlutterPathLayout<int>(
  items: items,
  connectorStyle: const PathConnectorStyle.dashed(
    width: 4,
    color: Color(0xFF7C8794),
    curved: true,
  ),
  itemBuilder: (context, item, index) => Node(item: item),
)

Set curved: true to draw smooth connector segments instead of straight line segments. Curved connectors work with solid, dashed, progress-based, and segment-resolved connector styles.

FlutterPathLayout<int>(
  items: items,
  connectorStyle: const PathConnectorStyle.solid(
    width: 5,
    color: Color(0xFF6B7280),
    curved: true,
  ),
  itemBuilder: (context, item, index) => Node(item: item),
)

Progress Styling #

Use PathLayoutProgress for simple paths where visual order and learning order are the same.

FlutterPathLayout<Activity>(
  items: activities,
  progress: const PathLayoutProgress(
    completedIndex: 4,
    currentIndex: 5,
    completedConnectorStyle: PathConnectorStyle.solid(
      color: Color(0xFF35A66F),
      width: 6,
      curved: true,
    ),
    pendingConnectorStyle: PathConnectorStyle.solid(
      color: Color(0xFFD1D5DB),
      width: 4,
      curved: true,
    ),
  ),
  contextItemBuilder: (context, activity, pathContext) {
    return ActivityNode(
      activity: activity,
      isCompleted: pathContext.isCompleted,
      isCurrent: pathContext.isCurrent,
      isPending: pathContext.isPending,
    );
  },
)

The package styles connector segments from the same geometry used for node placement. The consuming app still owns node visuals, including check marks, locked states, badges, rings, or current indicators.

Connector styles used by progress APIs can also be curved:

completedConnectorStyle: const PathConnectorStyle.solid(
  color: Color(0xFF35A66F),
  width: 6,
  curved: true,
)

For production paths where progress is keyed by backend IDs, visual order is reversed, or items can be skipped, prefer item-aware callbacks and a segment style resolver:

FlutterPathLayout<Activity>(
  items: renderedActivities,
  isItemCompleted: (activity, index) {
    return completedActivityIds.contains(activity.id);
  },
  isItemCurrent: (activity, index) {
    return activity.id == currentActivityId;
  },
  connectorStyleBuilder: (context, segment) {
    if (segment.isCompleted) {
      return const PathConnectorStyle.solid(
        color: Color(0xFF35A66F),
        width: 6,
        curved: true,
      );
    }

    return const PathConnectorStyle.solid(
      color: Color(0xFFD1D5DB),
      width: 4,
      curved: true,
    );
  },
  contextItemBuilder: (context, activity, pathContext) {
    return ActivityNode(
      activity: activity,
      isCompleted: pathContext.isCompleted,
      isCurrent: pathContext.isCurrent,
    );
  },
)

connectorStyleBuilder receives a PathSegmentContext<T> with fromItem, toItem, fromIndex, toIndex, geometry, direction, and resolved endpoint states. This lets the app keep progress key-based while the package owns connector painting.

Progress precedence is:

  • connectorBuilder
  • connectorStyleBuilder
  • PathLayoutProgress
  • connectorStyle

Item state precedence is:

  • isItemCompleted / isItemCurrent
  • PathLayoutProgress
  • pending by default

For fully custom connector visuals, use connectorBuilder:

FlutterPathLayout<int>(
  items: items,
  connectorBuilder: (context, geometry) {
    return CustomPaint(painter: MyRoadPainter(geometry));
  },
  itemBuilder: (context, item, index) => Node(item: item),
)

Path Corridors #

Use corridorStyle to paint a larger path around the connector centerline. The corridor can draw two adjustable bank lines, fill the area between those lines, and tint the area outside them.

FlutterPathLayout<int>(
  items: items,
  corridorStyle: const PathCorridorStyle(
    bankOffset: 96,
    bankWidth: 5,
    bankColor: Color(0xFF111111),
    insideColor: Color(0x22FFFFFF),
    outsideColor: Color(0x14000000),
    startExtension: 96,
    endExtension: 96,
  ),
  connectorStyle: const PathConnectorStyle.solid(
    color: Color(0xFF35A66F),
    width: 8,
    curved: true,
  ),
  itemBuilder: (context, item, index) => Node(item: item),
)

bankOffset controls the distance from the base path to each bank. bankWidth controls the stroke width of the two bank lines. startExtension and endExtension extend the corridor beyond the first and last nodes. The path stack defaults to Clip.none, so corridor banks can visually extend beyond the layout bounds when the base path runs close to an edge.

For textured banks, pass a custom bankShader, such as an ImageShader. For a lightweight striped texture, pass a shader gradient:

corridorStyle: const PathCorridorStyle(
  bankOffset: 96,
  bankWidth: 8,
  bankGradient: LinearGradient(
    begin: Alignment.topLeft,
    end: Alignment.bottomRight,
    colors: <Color>[
      Color(0xFF111111),
      Color(0xFF111111),
      Color(0xFF6B7280),
      Color(0xFF6B7280),
    ],
    stops: <double>[0, 0.5, 0.5, 1],
    tileMode: TileMode.repeated,
  ),
)

Performance Guidance #

This package uses a regular scroll view and stack. It is simple, predictable, and appropriate for typical learning paths. It currently builds all node widgets, so extremely large paths with hundreds or thousands of expensive nodes should be split into sections or paired with lightweight node widgets.

The package keeps geometry calculation separate from rendering so a future sliver or render-object implementation can reuse the same strategy model.

Architecture Overview #

  • FlutterPathLayout owns scrolling, measuring children, and widget placement.
  • PathLayoutEngine converts constraints, padding, child sizes, and strategy output into pixel geometry.
  • PathLayoutStrategy implementations return normalized cross-axis positions.
  • PathConnectorPainter paints optional connectors from the same geometry used by the nodes.

Run checks from this package directory:

fvm flutter analyze
fvm flutter test

From the repository root, the package also participates in the pnpm/Turbo workspace through its wrapper scripts:

pnpm --filter @mybaby/flutter-path-layout lint
pnpm --filter @mybaby/flutter-path-layout test

Example App #

The example app demonstrates vertical wave, horizontal wave, zigzag, straight, mixed node sizes, a custom strategy, connector styles, and progress styling.

cd packages/flutter_path_layout/example
fvm flutter run -d web-server --web-port 8090
1
likes
160
points
204
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Reusable Flutter layouts for learning, activity, roadmap, and progression paths.

Repository (GitHub)
View/report issues

Topics

#flutter #layout #path #roadmap #learning

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on flutter_path_layout