SubAspectComponent class
A stateful widget rendering a responsive sub-video area with dynamic dimension management.
Displays a secondary video/content area (typically positioned at bottom-left) that adapts to screen dimensions and control visibility state. Commonly used for screenshare previews, mini video players, control overlays, or audio participant grids.
Lifecycle & State Management:
- Tracks computed
_width
and_height
based on screen size and configuration - Recalculates dimensions in
didChangeDependencies()
(screen rotation, initial build) - Recalculates dimensions in
didUpdateWidget()
when showControls, fractions, or defaultFractionSub change - Uses
MediaQuery.of(context).size
to get current screen dimensions
Rendering Pipeline:
1. Create Stack with children (clipBehavior applied)
2. Call contentBuilder (if provided) to wrap Stack
3. Build Container with:
- Computed width (_width)
- Computed height (_height if showControls=true, else 0)
- Decoration (containerDecoration or backgroundColor)
- Padding, margin, alignment
4. Call containerBuilder (if provided) to customize Container
5. Wrap in Positioned(bottom: 0, left: 0) for absolute positioning
6. Call wrapperBuilder (if provided) to customize positioning
7. Wrap in Visibility widget (visible only if showControls=true)
Dimension Calculation Details:
// Width calculation:
widthFraction = (containerWidthFraction ?? 1.0).clamp(0.0, 1.0);
_width = widthFraction * MediaQuery.of(context).size.width;
// Height calculation (only if showControls = true):
if (containerHeightFraction != null) {
heightFraction = containerHeightFraction.clamp(0.0, 1.0);
_height = heightFraction * screenHeight;
} else if (0 < defaultFractionSub <= 1) {
_height = defaultFractionSub * screenHeight; // fractional mode
} else if (defaultFractionSub > 1) {
_height = defaultFractionSub; // fixed pixel mode
} else {
_height = 40; // minimum fallback
}
// When showControls = false:
_height = 0; (container collapses, Visibility hides entire widget)
Builder Hook Priorities:
contentBuilder
: Wrap Stack of children (e.g., add border around entire content area)containerBuilder
: Customize Container with dimensions (e.g., apply gradient, adjust padding)wrapperBuilder
: Customize Positioned widget (e.g., reposition from bottom-left to top-right)
Common Use Cases:
-
Screenshare Preview at Bottom:
SubAspectComponent( options: SubAspectComponentOptions( backgroundColor: Colors.black, children: [ VideoCard( options: VideoCardOptions( videoStream: screenshareStream, participant: presenter, parameters: parameters, ), ), ], showControls: parameters.shared, // visible only when screensharing active containerHeightFraction: 0.3, // 30% of screen height containerWidthFraction: 0.5, // 50% of screen width padding: EdgeInsets.all(8), containerDecoration: BoxDecoration( border: Border.all(color: Colors.blue, width: 2), borderRadius: BorderRadius.circular(8), ), ), )
-
Fixed-Height Control Bar:
SubAspectComponent( options: SubAspectComponentOptions( backgroundColor: Colors.grey[900]!, children: [ ControlButtonsComponent( options: ControlButtonsComponentOptions( buttons: allButtons, parameters: parameters, ), ), ], showControls: true, defaultFractionSub: 80.0, // 80 pixels fixed height alignment: Alignment.center, ), )
-
Mini Video Player (Top-Right):
SubAspectComponent( options: SubAspectComponentOptions( backgroundColor: Colors.black, children: [ VideoCard( options: VideoCardOptions( videoStream: localStream, participant: localParticipant, parameters: parameters, ), ), ], showControls: true, defaultFractionSub: 0.2, // 20% of screen height containerWidthFraction: 0.25, // 25% of screen width wrapperBuilder: (context) { return Positioned( top: 16, right: 16, child: context.container, ); }, containerDecoration: BoxDecoration( borderRadius: BorderRadius.circular(12), boxShadow: [BoxShadow(color: Colors.black45, blurRadius: 6)], ), ), )
-
Audio Participant Grid (Compact):
SubAspectComponent( options: SubAspectComponentOptions( backgroundColor: Colors.transparent, children: [ AudioGrid( options: AudioGridOptions( componentsToRender: audioCards, ), ), ], showControls: parameters.audioOnlyRoom, defaultFractionSub: 100.0, // 100 pixels for audio cards padding: EdgeInsets.symmetric(horizontal: 8), ), )
Override Integration:
Integrates with MediasfuUICustomOverrides
for global styling:
overrides: MediasfuUICustomOverrides(
subAspectComponentOptions: ComponentOverride<SubAspectComponentOptions>(
builder: (existingOptions) => SubAspectComponentOptions(
backgroundColor: existingOptions.backgroundColor,
children: existingOptions.children,
showControls: existingOptions.showControls,
defaultFractionSub: 0.25, // Always use 25% height
containerWidthFraction: 0.4, // Always use 40% width
containerDecoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.black87, Colors.grey[850]!],
),
borderRadius: BorderRadius.circular(16),
),
padding: EdgeInsets.all(12),
margin: EdgeInsets.only(bottom: 16, left: 16),
),
),
),
Responsive Behavior:
- Dimensions recalculate automatically on orientation change (via
didChangeDependencies
) - Width/height update immediately when fractions change (via
didUpdateWidget
) - Container collapses to zero height when
showControls = false
(smooth hide/show) - Fractional sizing adapts to different screen sizes (tablet, phone, desktop)
State Update Triggers:
showControls
change → height recalculated (collapse or expand)containerWidthFraction
change → width recalculatedcontainerHeightFraction
change → height recalculateddefaultFractionSub
change → height recalculated (if containerHeightFraction null)- Screen rotation → all dimensions recalculated (didChangeDependencies)
Performance Notes:
- Stateful widget (maintains _width and _height state)
- setState() called only when dimensions change (not every frame)
- Builder hooks called during every build (not cached)
- Positioned widget prevents layout reflow (absolute positioning)
- Visibility widget efficiently hides without removing from tree
Implementation Details:
- Uses
MediaQuery.of(context).size
for screen dimensions - Clamps fractions to
0.0, 1.0
range to prevent invalid sizes - Checks
mounted
before calling setState() (prevents errors after dispose) - Stack uses
clipBehavior
from options (defaults to Clip.hardEdge) - Container dimensions default to full width if no fraction provided
- Positioned always places container at bottom-left unless wrapperBuilder overrides
Typical Usage Context:
- Secondary video area in video conferencing
- Screenshare preview overlay
- Control button panel at bottom
- Mini participant video (picture-in-picture style)
- Audio-only participant list (compact view)
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- SubAspectComponent
Constructors
- SubAspectComponent({Key? key, required SubAspectComponentOptions 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 → SubAspectComponentOptions
-
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(
) → State< SubAspectComponent> -
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