buildM3ESimpleBody function
Widget
buildM3ESimpleBody(
- BuildContext context,
- M3EExpandableData data,
- double progress,
- M3EExpandableStyle decoration,
Implementation
Widget buildM3ESimpleBody(
BuildContext context,
M3EExpandableData data,
double progress,
M3EExpandableStyle decoration,
) {
final List<Widget> children = [];
if (data.subtitle != null && data.subtitle!.isNotEmpty) {
// Resolve subtitle styles based on user input
TextStyle collapsedSubtitleStyle;
TextStyle expandedSubtitleStyle;
if (data.subtitleStyle != null && data.subtitleStyle!.length == 2) {
collapsedSubtitleStyle = data.subtitleStyle![0];
expandedSubtitleStyle = data.subtitleStyle![1];
} else if (data.subtitleStyle != null && data.subtitleStyle!.length == 1) {
collapsedSubtitleStyle = data.subtitleStyle![0];
expandedSubtitleStyle = data.subtitleStyle![0];
} else {
final defaultStyle = Theme.of(context).textTheme.bodyMedium!;
collapsedSubtitleStyle = defaultStyle;
expandedSubtitleStyle = defaultStyle;
}
final alignment = decoration.bodyAlignment;
final maxLines = data.subtitleMaxLines ?? 1;
// Determine TextAlign based on AlignmentGeometry roughly
TextAlign mappedTextAlign = TextAlign.start;
if (alignment == Alignment.topCenter ||
alignment == Alignment.center ||
alignment == Alignment.bottomCenter) {
mappedTextAlign = TextAlign.center;
} else if (alignment == Alignment.topRight ||
alignment == Alignment.centerRight ||
alignment == Alignment.bottomRight) {
mappedTextAlign = TextAlign.right;
}
// Smooth crossfade: use hard switch at midpoint to avoid flicker
// We keep the Stack based approach to preserve the exact UI requested,
// but ensure it's clean and handles progress correctly.
final showCollapsedSubtitle = progress < 0.5;
final showExpandedSubtitle = progress >= 0.5;
children.add(
Padding(
padding: EdgeInsets.only(top: decoration.titleSubtitleGap),
child: Stack(
children: [
if (showCollapsedSubtitle)
Align(
alignment: alignment,
child: Text(
data.subtitle!,
maxLines: maxLines,
overflow: TextOverflow.ellipsis,
style: collapsedSubtitleStyle,
textAlign: mappedTextAlign,
),
),
if (showExpandedSubtitle)
ClipRect(
child: Align(
alignment: alignment,
heightFactor: 1.0,
child: Text(
data.subtitle!,
style: expandedSubtitleStyle,
textAlign: mappedTextAlign,
),
),
),
],
),
),
);
}
if ((data.body != null || data.bodyBuilder != null) && progress > 0.0) {
children.add(
ClipRect(
child: Align(
alignment: decoration.bodyAlignment,
heightFactor: progress.clamp(0.0, 1.0),
child: Padding(
padding: EdgeInsets.only(top: children.isEmpty ? 0 : 12),
child: data.bodyBuilder?.call(context) ?? data.body!,
),
),
),
);
}
if (children.isEmpty) return const SizedBox.shrink();
if (children.length == 1) return children.first;
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: children,
);
}