buildLayer method
- BuildContext context,
- List<
MorphGlassSurface> surfaces, { - Widget? content,
- List<
Rect> contentSlots = const [], - double spacing = 0,
- MorphGlassOutline? outline,
Builds one glass layer of a control: its surfaces, back to front,
in a box that fills the layer, with the control's content over
them.
The surfaces of one call belong to one control and move together, so
a painter can render them as a unit: share one backdrop sample, fuse
neighbors, or show content through a lens. The default places each
surface at its bounds, from buildSurface when it is glass and from
buildFill when it is not, and content over them.
contentSlots are the boxes of the items of content - the segments
of a segmented control, the tabs of a tab bar - in the layer's local
coordinates, each item centered in its box. They stay put while a
lens moves over them. A painter that magnifies the content seen
through a lens scales each item about the center of its own slot and
clips it to that slot, so a label under a moving lens grows in place
and never slides; only the lens window moves. Empty means the content
is one item that fills the layer.
A positive spacing makes the glass surfaces one glass container
with that spacing, as UIKit's UIGlassContainerEffect and SwiftUI's
GlassEffectContainer do: two surfaces closer than spacing lean
toward each other and share a body when their gap is less than
spacing - 0.5, by the
merge law of the skin (whose blend width the spacing
is, 1:1); surfaces spacing or more apart do not touch. Zero keeps
every surface separate. The bars pass 12, the spacing UIKit gives the
glass container of a navigation bar and of a toolbar, which is also
the gap between two groups of one bar: resting groups never fuse,
moving ones fuse while they pass closer.
A non-null outline is the silhouette the control has already fused
its glass surfaces into, in the layer's local coordinates: the glass
surfaces are one body whose edge is outline, not their own shapes
(a menu joined to its button by a neck). A painter draws that body
with buildBody and does not fuse the surfaces again; their shapes
and kinds still describe the parts of the body. The default draws
buildBody in place of buildSurface for every glass surface.
Implementation
Widget buildLayer(
BuildContext context,
List<MorphGlassSurface> surfaces, {
Widget? content,
List<Rect> contentSlots = const [],
double spacing = 0,
MorphGlassOutline? outline,
}) {
final glass = [
for (final surface in surfaces)
if (surface.glass) surface,
];
return Stack(
clipBehavior: Clip.none,
children: [
if (outline != null && glass.isNotEmpty)
Positioned.fill(child: buildBody(context, outline, glass)),
for (final surface in surfaces)
if (outline == null || !surface.glass)
Positioned.fromRect(
rect: surface.bounds,
child: surface.glass
? buildSurface(context, surface)
: buildFill(context, surface),
),
if (content != null)
Positioned.fill(
key: const ValueKey<String>('content'),
child: content,
),
],
);
}