VPositioned¶
Video-aware Positioned with timing, fading, and hero transitions
VPositioned extends Flutter's Positioned with video-specific properties including startFrame, endFrame, fade transitions, and hero-style cross-scene animations.
Table of Contents¶
Overview¶
VPositioned positions content within a Stack or VStack while adding video timing capabilities:
VStack(
children: [
VPositioned(
left: 100,
top: 200,
startFrame: 30,
fadeInFrames: 15,
child: Text('Positioned Content'),
),
],
)
When to Use¶
Use VPositioned when you need:
- Positioned content that appears/disappears at specific frames
- Positioned content with fade in/out transitions
- Hero-style animations between scenes
- Absolute positioning with video timing
Properties¶
Positioned Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
child |
Widget |
required | Widget to position |
left |
double? |
null |
Distance from left edge |
top |
double? |
null |
Distance from top edge |
right |
double? |
null |
Distance from right edge |
bottom |
double? |
null |
Distance from bottom edge |
width |
double? |
null |
Fixed width |
height |
double? |
null |
Fixed height |
Video Timing Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
startFrame |
int? |
null |
Frame to become visible |
endFrame |
int? |
null |
Frame to become invisible |
fadeInFrames |
int |
0 |
Fade-in duration in frames |
fadeOutFrames |
int |
0 |
Fade-out duration in frames |
fadeInCurve |
Curve |
easeOut |
Fade-in easing |
fadeOutCurve |
Curve |
easeIn |
Fade-out easing |
Hero Property¶
| Property | Type | Default | Description |
|---|---|---|---|
heroKey |
GlobalKey? |
null |
Key for cross-scene hero animations |
Constructors¶
Default Constructor¶
VPositioned.fill¶
Fill the entire Stack:
VPositioned.fromOffset¶
Create from an Offset:
VPositioned.fromRect¶
Create from a Rect:
Examples¶
Basic Positioning¶
VStack(
children: [
VPositioned(
left: 50,
top: 100,
child: Text('Top Left Area'),
),
VPositioned(
right: 50,
bottom: 100,
child: Text('Bottom Right Area'),
),
],
)
With Timing¶
VStack(
children: [
// Title appears at frame 30
VPositioned(
left: 0,
right: 0,
top: 100,
startFrame: 30,
fadeInFrames: 20,
child: Text(
'Welcome',
textAlign: TextAlign.center,
style: titleStyle,
),
),
// Subtitle appears at frame 50
VPositioned(
left: 0,
right: 0,
top: 200,
startFrame: 50,
fadeInFrames: 20,
child: Text(
'to your story',
textAlign: TextAlign.center,
style: subtitleStyle,
),
),
],
)
Fill Background¶
VStack(
children: [
VPositioned.fill(
startFrame: 0,
fadeInFrames: 30,
child: Image.asset('assets/bg.jpg', fit: BoxFit.cover),
),
VPositioned(
left: 50,
right: 50,
bottom: 100,
startFrame: 30,
fadeInFrames: 20,
child: Text('Overlay Text'),
),
],
)
Gradient Overlay¶
VStack(
children: [
// Image background
VPositioned.fill(
child: Image.asset('assets/photo.jpg', fit: BoxFit.cover),
),
// Gradient for text readability
VPositioned(
left: 0,
right: 0,
bottom: 0,
height: 300,
startFrame: 0,
fadeInFrames: 20,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [Colors.black87, Colors.transparent],
),
),
),
),
// Text at bottom
VPositioned(
left: 50,
right: 50,
bottom: 50,
startFrame: 30,
fadeInFrames: 20,
child: Text('Photo Caption', style: captionStyle),
),
],
)
Corner Positioned Elements¶
VStack(
children: [
// Top left
VPositioned(
left: 20,
top: 20,
startFrame: 0,
fadeInFrames: 15,
child: Logo(),
),
// Top right
VPositioned(
right: 20,
top: 20,
startFrame: 10,
fadeInFrames: 15,
child: DateWidget(),
),
// Bottom left
VPositioned(
left: 20,
bottom: 20,
startFrame: 20,
fadeInFrames: 15,
child: Watermark(),
),
// Bottom right
VPositioned(
right: 20,
bottom: 20,
startFrame: 30,
fadeInFrames: 15,
child: SocialHandle(),
),
],
)
Hero Transitions¶
VPositioned supports hero-style transitions between scenes. When two VPositioned widgets in adjacent scenes share the same heroKey, the Video widget automatically animates between their positions during scene transitions.
Basic Hero Animation¶
final photoKey = GlobalKey();
Video(
fps: 30,
width: 1920,
height: 1080,
defaultTransition: SceneTransition.crossFade(durationInFrames: 30),
scenes: [
// Scene 1: Photo in center
Scene(
durationInFrames: 90,
children: [
VPositioned(
left: 710, // Centered
top: 340,
width: 500,
height: 400,
heroKey: photoKey,
child: Image.asset('assets/photo.jpg'),
),
],
),
// Scene 2: Photo moves to corner
Scene(
durationInFrames: 90,
children: [
VPositioned(
left: 50, // Top left corner
top: 50,
width: 200,
height: 160,
heroKey: photoKey, // Same key = animates position
child: Image.asset('assets/photo.jpg'),
),
VPositioned(
left: 300,
top: 50,
child: Text('Your favorite photo'),
),
],
),
],
)
Hero Animation Properties¶
The hero animation automatically interpolates:
- Position (left, top, right, bottom)
- Size (width, height)
- Transform (if specified)
Requirements for Hero Transitions¶
- Both
VPositionedwidgets must have the sameheroKey - A scene transition must be set on the
Videowidget - The widgets should be in adjacent scenes
Complete Example¶
Scene(
durationInFrames: 180,
background: Background.solid(Colors.black),
children: [
// Background image
VPositioned.fill(
fadeInFrames: 30,
child: Opacity(
opacity: 0.3,
child: Image.asset('assets/bg.jpg', fit: BoxFit.cover),
),
),
// Main title
VPositioned(
left: 0,
right: 0,
top: 200,
startFrame: 30,
fadeInFrames: 25,
child: Text(
'2024',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 120,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
// Subtitle
VPositioned(
left: 0,
right: 0,
top: 350,
startFrame: 50,
fadeInFrames: 25,
child: Text(
'YOUR YEAR IN REVIEW',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 36,
color: Colors.white70,
letterSpacing: 8,
),
),
),
// Stats at bottom
VPositioned(
left: 50,
right: 50,
bottom: 150,
startFrame: 75,
fadeInFrames: 25,
child: VRow(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
stagger: StaggerConfig.slideUp(delay: 10),
children: [
StatWidget(value: '2,451', label: 'Minutes'),
StatWidget(value: '128', label: 'Songs'),
StatWidget(value: '32', label: 'Artists'),
],
),
),
],
)
Related¶
- VStack - Stack with timing
- LayerStack - Layer-based composition
- Layer - Layer with timing
- VCenter - Center with timing