MainAspectComponent class
A stateful widget rendering the primary responsive video area with real-time screen size detection.
Manages the main video/content container that adapts to screen dimensions, orientation changes, and control visibility. Implements WidgetsBindingObserver to detect screen metric changes and invokes callbacks to update parent state for responsive layout adjustments across the app.
Lifecycle & Observers:
- Implements
WidgetsBindingObserver
to listen for screen metric changes - Registers observer in
initState()
(adds addPostFrameCallback for initial calculation) - Removes observer in
dispose()
to prevent memory leaks didChangeMetrics()
called automatically on screen rotation, resize, keyboard visibility
Dimension Calculation (performed in _updateAspectStyles()
):
// Computed dimensions:
parentWidth = screenWidth * containerWidthFraction
// Height depends on showControls flag:
if (showControls) {
parentHeight = screenHeight * containerHeightFraction * defaultFraction
// Example: 1920 * 1.0 * 0.94 = 1804.8px (reserves 6% for controls)
} else {
parentHeight = screenHeight * containerHeightFraction - safeAreaTop
// Example: 1920 * 1.0 - 44 = 1876px (full height minus notch)
}
Screen Size Classification Logic:
// Initial classification based on width:
isWideScreen = parentWidth > 768
isMediumScreen = parentWidth > 576 && parentWidth <= 768
isSmallScreen = parentWidth <= 576
// Override for very wide aspect ratios:
if (parentWidth > 1.5 * parentHeight) {
isWideScreen = true
isMediumScreen = false
isSmallScreen = false
}
// This handles landscape tablets/desktops with wide aspect ratios
Callback Execution Flow:
1. Screen metric change detected (rotation, resize, keyboard)
2. didChangeMetrics() called by WidgetsBinding
3. _updateAspectStyles() calculates new dimensions
4. Screen size breakpoints evaluated
5. Callbacks invoked with new boolean states:
- updateIsWideScreen(bool)
- updateIsMediumScreen(bool)
- updateIsSmallScreen(bool)
6. setState() called to trigger rebuild with new dimensions
7. Parent state updates (via callbacks) trigger other responsive adjustments
Rendering Structure:
Container
├─ color: backgroundColor
├─ width: parentWidth (calculated)
├─ height: parentHeight (calculated)
└─ child: Stack
├─ children[0] (typically MainGridComponent)
├─ children[1] (e.g., audio indicators)
└─ children[N] (e.g., overlays)
Common Use Cases:
-
Full-Screen Video Conference:
MainAspectComponent( options: MainAspectComponentOptions( backgroundColor: Colors.black, children: [ MainGridComponent( options: MainGridComponentOptions( mainSize: mainGridStream != null ? mainGridStream!.length : 0, height: parameters.componentSizes.mainHeight, width: parameters.componentSizes.mainWidth, backgroundColor: Colors.grey[900]!, children: mainGridStreams, showAspect: showMainVideo, timeBackgroundColor: Colors.green, meetingProgressTime: parameters.meetingProgressTime, ), ), ], showControls: true, // reserves space for control bar containerWidthFraction: 1.0, containerHeightFraction: 1.0, defaultFraction: 0.94, // 94% height for video, 6% for controls updateIsWideScreen: (isWide) { parameters.updateIsWideScreen(isWide); // Trigger grid layout recalculation }, updateIsMediumScreen: (isMed) { parameters.updateIsMediumScreen(isMed); }, updateIsSmallScreen: (isSmall) { parameters.updateIsSmallScreen(isSmall); }, ), )
-
Screenshare Display (No Control Bar):
MainAspectComponent( options: MainAspectComponentOptions( backgroundColor: Colors.black, children: [ VideoCard( options: VideoCardOptions( videoStream: screenshareStream, participant: presenter, parameters: parameters, ), ), ], showControls: false, // full height minus safe area containerWidthFraction: 1.0, containerHeightFraction: 1.0, defaultFraction: 1.0, // not applied when showControls=false updateIsWideScreen: (isWide) => handleScreenResize(isWide), updateIsMediumScreen: (_) {}, updateIsSmallScreen: (_) {}, ), )
-
Split-Screen Layout:
MainAspectComponent( options: MainAspectComponentOptions( backgroundColor: Colors.grey[900]!, children: [ Row( children: [ Expanded(child: videoGrid), // main participants Expanded(child: screenshareView), // shared content ], ), ], showControls: true, containerWidthFraction: 1.0, containerHeightFraction: 1.0, defaultFraction: 0.92, // slightly more space for controls updateIsWideScreen: (isWide) { // Switch to vertical layout if not wide if (!isWide) { updateLayout(LayoutMode.vertical); } else { updateLayout(LayoutMode.horizontal); } }, updateIsMediumScreen: (_) {}, updateIsSmallScreen: (_) {}, ), )
-
Responsive Gallery Mode:
MainAspectComponent( options: MainAspectComponentOptions( backgroundColor: Colors.black, children: [ FlexibleGrid( options: FlexibleGridOptions( customWidth: parameters.componentSizes.mainWidth, customHeight: parameters.componentSizes.mainHeight, rows: parameters.gridRows, columns: parameters.gridCols, componentsToRender: allParticipantCards, backgroundColor: Colors.transparent, ), ), ], showControls: true, containerWidthFraction: 1.0, containerHeightFraction: 1.0, defaultFraction: 0.94, updateIsWideScreen: (isWide) { // Adjust grid dimensions based on screen size parameters.updateIsWideScreen(isWide); if (isWide) { parameters.updateGridCols(4); // more columns on wide screens } else { parameters.updateGridCols(2); // fewer columns on narrow screens } }, updateIsMediumScreen: (isMed) { parameters.updateIsMediumScreen(isMed); if (isMed) parameters.updateGridCols(3); }, updateIsSmallScreen: (isSmall) { parameters.updateIsSmallScreen(isSmall); if (isSmall) parameters.updateGridCols(1); }, ), )
Override Integration: Override not typically used for MainAspectComponent (core layout component), but dimensions can be influenced via parameters:
// In parameters initialization:
parameters.updateComponentSizes(ComponentSizesType(
mainHeight: MediaQuery.of(context).size.height * 0.94,
mainWidth: MediaQuery.of(context).size.width,
otherHeight: MediaQuery.of(context).size.height * 0.06,
otherWidth: MediaQuery.of(context).size.width,
));
Responsive Behavior:
- Automatically recalculates dimensions on orientation change (portrait ↔ landscape)
- Updates screen size states when keyboard appears/disappears (height change)
- Adjusts for safe area insets (notch, status bar) when showControls=false
- Invokes callbacks to propagate screen size changes to parent state
- Rebuilds only when dimensions change (not on every frame)
State Update Triggers:
- Orientation change → didChangeMetrics() → _updateAspectStyles() → callbacks + setState()
- Screen resize (desktop window) → didChangeMetrics() → recalculation
- Keyboard visibility change → didChangeMetrics() → height recalculation
- Initial build → addPostFrameCallback → _updateAspectStyles()
- showControls prop change → widget update → build with new height logic
Performance Notes:
- Stateful widget (maintains no internal state beyond component lifecycle)
- Uses WidgetsBindingObserver for efficient screen metric listening
- Callbacks invoked only on actual dimension changes (not every frame)
- setState() called only when screen metrics change (efficient rebuilds)
- Stack renders all children without lazy loading (suitable for small child count)
Implementation Details:
- Calculates parentWidth/parentHeight fresh on every build (no caching)
- Safe area insets include both padding and systemGestureInsets
- Aspect ratio override (width > 1.5 * height) handles ultra-wide displays
- Checks
mounted
before setState() to prevent errors after dispose - Container uses calculated dimensions (no intrinsic sizing)
Typical Usage Context:
- Primary video area in video conferencing apps
- Main stage for webinar/broadcast applications
- Central content area for screenshare display
- Gallery view container for participant grid
- Spotlight mode for single active speaker
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- MainAspectComponent
Constructors
- MainAspectComponent.new({Key? key, required MainAspectComponentOptions options})
-
const
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
- options → MainAspectComponentOptions
-
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → _MainAspectComponentState -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited