Skip to content

`TrackedMovementView`

The drop-in widget that bundles camera + pose detection + tracking into one mountable surface. Most consumers use this; only reach for MovementTracker + PoseCameraView manually when you need a custom layout (e.g. a non-camera pose source like recorded video).

TrackedMovementView(
cameras: cameras,
movement: myMovement,
onRepCompleted: (event) => …,
onTrackingResult: (result) => …,
)

Constructor

const TrackedMovementView({
required List<CameraDescription> cameras,
required Movement movement,
MovementConfig? movementConfig,
MovementTrackerPreset? preset,
MovementTrackerConfig? config,
OnTrackingResult? onTrackingResult,
OnRepCompleted? onRepCompleted,
OnPositionChange? onPositionChange,
OnFormFeedback? onFormFeedback,
VoidCallback? onReady,
void Function(String error)? onError,
Widget? overlay,
Widget Function(BuildContext, TrackedMovementState)? overlayBuilder,
bool showSkeleton = true,
bool showControls = false,
int? initialCameraIndex,
Widget? loadingWidget,
ResolutionPreset resolutionPreset = ResolutionPreset.medium,
bool pipelined = true,
BlazeFlowBackend? backend,
ExecutionConfig? executionConfig,
int isolateCount = 1,
bool syncedFrameMode = false,
int displayFrameMaxDimension = 480,
bool preferCpu = false,
});

Required

camerasFrom await availableCameras().
movementThe loaded Movement.

Optional

movementConfigA CMS-published MovementConfig overlay. When present, its trackingPoints / phases / formRules override the inline values from the .pose file.
presetOne of casual, standard, strict, competition. Mutually exclusive with config.
configA full MovementTrackerConfig. Takes precedence over preset.
showSkeletonDraw the pose skeleton overlay. Default true.
showControlsShow camera-switch + flash controls. Default false.
initialCameraIndexWhich camera to start with. Default 0 (usually rear; pick the front-facing index for selfie mode).
resolutionPresetCamera capture preset. Default medium (~720p).
pipelinedDouble-buffered pose inference. Default true.
backendHardware backend for the pose engine. Null = auto-select.
executionConfigFull PoseFlow’s native runtime execution config. Overrides backend.
isolateCountBackground isolates for inference. 1 by default; bump to 2-4 on multi-core targets if you need higher FPS.
syncedFrameModeDisplay the processed frame instead of the live preview. Eliminates skeleton/image lag at the cost of ~1 frame of latency.
preferCpuForce the CPU backend on Android even when NNAPI is available.

Callbacks

typedef OnTrackingResult = void Function(TrackingResult result);
typedef OnRepCompleted = void Function(RepCompletedEvent event);
typedef OnPositionChange = void Function(PositionChangeEvent event);
typedef OnFormFeedback = void Function(FormFeedbackEvent event);

onTrackingResult fires every frame, use it for live HUD updates (form score badge, current phase indicator, etc.).

onRepCompleted fires once per completed rep, use it for the rep counter, audio beep, haptic feedback.

onFormFeedback fires per form-cue event, use it for the toast deck, audio cue, vibration burst.

onPositionChange fires when the vector matcher’s committed position label changes, useful for “you’re in the down position” type cues.

Overlay options

Two ways to draw on top of the camera + skeleton:

overlay, a static Widget painted above the skeleton:

TrackedMovementView(
...
overlay: const Center(child: Text('Squat in front of the camera')),
)

overlayBuilder, receives the current TrackedMovementState on every rebuild:

TrackedMovementView(
...
overlayBuilder: (context, state) {
return Positioned(
top: 60,
left: 24,
child: Text('Reps: ${state.repCount}'),
);
},
)

TrackedMovementState

The widget’s externally-visible state, exposed via the builder:

class TrackedMovementState {
final TrackingResult? result;
final int repCount;
final double formScore;
final String? position;
final RepQuality? lastRepQuality;
final bool isTracking;
final List<String> activeFeedback;
final List<RepCompletedEvent> recentReps; // last 5
}

Imperative methods

The widget exposes a GlobalKey<TrackedMovementViewState> if you need to drive it from outside:

final key = GlobalKey<TrackedMovementViewState>();
TrackedMovementView(key: key, ...)
// Later:
key.currentState?.reset(); // start a new set
key.currentState?.pause();
key.currentState?.resume();

Under the hood

TrackedMovementView internally builds args via LoadMovementArgs.from(...).applyTo(tracker). Same convention as every other consumer. There is no magic involved, you could reproduce its behaviour by mounting PoseCameraView + a MovementTracker yourself; the widget just bundles them so the common case is one line.