buildFluentDivider function
Widget
buildFluentDivider(
- FluentDividerBaseState state,
- FluentDividerStyle style,
- Set<
WidgetState> states
Renders a divider from a resolved state and style.
The third of the three-function recomposition contract. Takes FluentDividerBaseState rather than FluentDividerState on purpose: it never reads appearance or inset, so a consumer can supply their own style and still use Fluent's rendering.
states exists for symmetry with the interactive components and is always
empty in practice — a divider has no interaction states to report. It is
still honoured, so a caller passing a state-dependent style gets what they
asked for.
Implementation
Widget buildFluentDivider(
FluentDividerBaseState state,
FluentDividerStyle style,
Set<WidgetState> states,
) {
final lineColor = style.lineColor?.resolve(states);
final thickness = style.lineThickness?.resolve(states) ?? FluentStroke.thin;
final shortLength = style.shortLineLength?.resolve(states) ?? FluentSpacing.s;
final contentColor = style.contentColor?.resolve(states);
final textStyle = style.textStyle?.resolve(states);
final padding = style.padding?.resolve(states) ?? EdgeInsets.zero;
final contentPadding =
style.contentPadding?.resolve(states) ?? EdgeInsets.zero;
final contentMinimum = style.contentMinimumSize?.resolve(states) ?? Size.zero;
final gap = style.gap?.resolve(states) ?? FluentSpacing.sNudge;
final iconSize = style.iconSize?.resolve(states) ?? FluentSize.size200;
final vertical = state.vertical;
// A hairline that stretches on one axis and is pinned on the other. The
// colour is only painted when a token was actually resolved: an absent colour
// must leave the rule unpainted rather than fall back to a literal
// transparent, which would stay invisible in high contrast where Fluent's
// transparent tokens turn opaque.
Widget rule({required bool flexible}) {
final line = SizedBox(
width: vertical ? thickness : (flexible ? null : shortLength),
height: vertical ? (flexible ? null : shortLength) : thickness,
child: lineColor == null ? null : ColoredBox(color: lineColor),
);
return flexible ? Expanded(child: line) : line;
}
Widget? content;
if (state.hasContent) {
Widget row = Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
spacing: state.icon != null && state.label != null ? gap : 0,
children: <Widget>[
if (state.icon != null)
IconTheme.merge(
data: IconThemeData(color: contentColor, size: iconSize),
child: state.icon!,
),
if (state.label != null) state.label!,
],
);
if (textStyle != null || contentColor != null) {
row = DefaultTextStyle.merge(
style: (textStyle ?? const TextStyle()).copyWith(color: contentColor),
child: row,
);
}
content = ConstrainedBox(
constraints: BoxConstraints(
minWidth: contentMinimum.width,
minHeight: contentMinimum.height,
),
child: Padding(padding: contentPadding, child: row),
);
}
// With no label there is nothing to align around, so the single rule spans the
// whole divider whatever `alignment` says.
final children = content == null
? <Widget>[rule(flexible: true)]
: <Widget>[
rule(flexible: state.alignment != FluentDividerAlignment.start),
content,
rule(flexible: state.alignment != FluentDividerAlignment.end),
];
return Padding(
padding: padding,
child: vertical
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
)
: Row(mainAxisAlignment: MainAxisAlignment.center, children: children),
);
}