GlassButton class

Glass morphism button with scale animation and glow effects.

This button provides a complete liquid glass experience with:

  • Liquid glass visual effect with customizable settings
  • Scale animation (squash & stretch) when pressed
  • Touch-responsive glow effect on interaction (Impeller) or shader-based glow (Skia)
  • Full control over all animation and visual properties
  • Accessibility support with semantic labels
  • Flexible content support (icon or custom child)

Platform Rendering

The glow effect adapts to the platform:

  • Impeller: Uses advanced compositing via GlassGlow
  • Skia/Web: Animates shader saturation parameter for frosted glow

Usage Modes

Grouped Mode (default)

Uses LiquidGlass.grouped and inherits settings from parent LiquidGlassLayer:

AdaptiveLiquidGlassLayer(
  settings: LiquidGlassSettings(...),
  child: Column(
    children: [
      GlassButton(
        icon: Icon(CupertinoIcons.heart),
        onTap: () => print('Favorite'),
      ),
    ],
  ),
)

Standalone Mode

Creates its own layer with LiquidGlass.withOwnLayer:

GlassButton(
  icon: Icon(CupertinoIcons.play),
  onTap: () => print('Play'),
  useOwnLayer: true,
  settings: LiquidGlassSettings(
    thickness: 0.3,
    blurRadius: 20,
  ),
)

Customization Examples

Custom stretch behavior:

GlassButton(
  icon: Icon(CupertinoIcons.star),
  onTap: () {},
  interactionScale: 1.1,  // Grow 10% when pressed
  stretch: 0.8,           // More dramatic stretch
  resistance: 0.15,       // Higher drag resistance
)

Custom glow effect:

GlassButton(
  icon: Icon(CupertinoIcons.bolt),
  onTap: () {},
  glowColor: Colors.blue.withOpacity(0.4),
  glowRadius: 1.5,  // Larger glow
)

Custom content:

GlassButton.custom(
  onTap: () {},
  width: 120,
  height: 48,
  child: Text('Click Me', style: TextStyle(color: Colors.white)),
)

When multiple buttons share a LiquidGlassBlendGroup (e.g. inside an AdaptiveLiquidGlassLayer), the drag-follow animation physically moves each button's glass shape in the shader's coordinate space. Because the blend group treats all shapes as a connected liquid surface, dragging one button causes neighboring buttons to visually respond — this is intentional for isolated floating buttons, but can feel jarring in a nav bar.

Reduce stretch for tightly-grouped buttons to keep the tactile press feel without excessive cross-button coupling:

// Nav bar / toolbar — subtle liquid feel, minimal coupling
GlassButton(
  stretch: 0.15,
  icon: Icon(CupertinoIcons.home),
  onTap: () {},
)

// Standalone FAB — full liquid feel (default)
GlassButton(
  icon: Icon(CupertinoIcons.add),
  onTap: () {},
)

Setting stretch to 0.0 disables drag-following entirely while keeping the press-scale effect (interactionScale).

Inheritance

Constructors

GlassButton({required Widget? icon, required VoidCallback onTap, Key? key, String label = '', double? width = 56, double? height = 56, double iconSize = 24.0, Color? iconColor, LiquidShape shape = const LiquidOval(), LiquidGlassSettings? settings, bool useOwnLayer = false, GlassQuality? quality, FocusNode? focusNode, bool autofocus = false, double interactionScale = 1.05, double stretch = 0.5, double resistance = 0.01, HitTestBehavior stretchHitTestBehavior = HitTestBehavior.opaque, Color? glowColor, double glowRadius = 1.0, double? glowBlurRadius, double? glowSpreadRadius, double? glowOpacity, HitTestBehavior glowHitTestBehavior = HitTestBehavior.opaque, bool enabled = true, GlassButtonStyle style = GlassButtonStyle.filled, bool persistPressOnDrag = true, bool anchorStretch = true, AnchorStretchSettings anchorStretchSettings = const AnchorStretchSettings(), AlignmentGeometry alignment = Alignment.center, double ambientBaseLight = 0.08, bool platformViewBackdrop = false, bool canRequestFocus = true, bool excludeFromSemantics = false})
Creates a glass button with an icon.
const
GlassButton.custom({required Widget? child, required VoidCallback onTap, Key? key, String label = '', double? width, double? height, LiquidShape shape = const LiquidOval(), LiquidGlassSettings? settings, bool useOwnLayer = false, GlassQuality? quality, FocusNode? focusNode, bool autofocus = false, double interactionScale = 1.05, double stretch = 0.5, double resistance = 0.01, HitTestBehavior stretchHitTestBehavior = HitTestBehavior.opaque, Color? glowColor, double glowRadius = 1.0, double? glowBlurRadius, double? glowSpreadRadius, double? glowOpacity, HitTestBehavior glowHitTestBehavior = HitTestBehavior.opaque, bool enabled = true, GlassButtonStyle style = GlassButtonStyle.filled, bool persistPressOnDrag = true, bool anchorStretch = true, AnchorStretchSettings anchorStretchSettings = const AnchorStretchSettings(), AlignmentGeometry alignment = Alignment.center, double ambientBaseLight = 0.08, bool platformViewBackdrop = false, bool canRequestFocus = true, bool excludeFromSemantics = false})
Creates a glass button with custom content.
const

Properties

alignment → AlignmentGeometry
How to align the child content within the button bounds.
final
ambientBaseLight → double
Opacity of the ambient base light when the button is pressed.
final
anchorStretch → bool
Whether the stretch anchors the button in place.
final
anchorStretchSettings → AnchorStretchSettings
Fine-tuning for the anchor stretch effect.
final
autofocus → bool
Whether this button should be focused automatically when it is inserted into the widget tree.
final
canRequestFocus → bool
Whether the button can request focus.
final
child → Widget?
Custom widget to display in the button.
final
enabled → bool
Whether the button is enabled.
final
excludeFromSemantics → bool
Whether to exclude this button from the semantics tree.
final
focusNode → FocusNode?
An optional focus node to use for this button.
final
glowBlurRadius → double?
Additional Gaussian blur sigma applied to the glow halo.
final
glowColor → Color?
The color of the glow effect.
final
glowHitTestBehavior → HitTestBehavior
The hit test behavior for the glow gesture listener.
final
glowOpacity → double?
Master opacity multiplier (0–1) applied on top of glowColor's alpha.
final
glowRadius → double
The radius of the glow effect relative to the layer's shortest side.
final
glowSpreadRadius → double?
Extra glow circle spread as a fraction of the layer's shortest side.
final
hashCode → int
The hash code for this object.
no setterinherited
height → double?
Height of the button in logical pixels.
final
icon → Widget?
The widget to display in the button.
final
iconColor → Color?
Color of the icon (only used when icon is provided).
final
iconSize → double
Size of the icon (only used when icon is provided).
final
interactionScale → double
The scale factor to apply when the user is interacting with the button.
final
key → Key?
Controls how one widget replaces another widget in the tree.
finalinherited
label → String
Semantic label for accessibility.
final
onTap → VoidCallback
Callback when the button is tapped.
final
persistPressOnDrag → bool
Whether the pressed glass distortion persists while the finger is held down, even if dragged far away from the button.
final
platformViewBackdrop → bool
When true (typically for iOS PlatformViews), forces the BackdropFilter fallback render path instead of the Impeller-native shader. Forwarded to the underlying AdaptiveGlass.
final
quality → GlassQuality?
Rendering quality for the glass effect.
final
resistance → double
The resistance factor to apply to the drag offset.
final
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
settings → LiquidGlassSettings?
Glass effect settings for the button.
final
shape → LiquidShape
Shape of the glass button.
final
stretch → double
The factor to multiply the drag offset by to determine the stretch amount.
final
stretchHitTestBehavior → HitTestBehavior
The hit test behavior for the stretch gesture listener.
final
style → GlassButtonStyle
The visual style of the button.
final
useOwnLayer → bool
Whether to create its own layer or use grouped glass within an existing layer.
final
width → double?
Width of the button in logical pixels.
final

Methods

createElement() → StatefulElement
Creates a StatefulElement to manage this widget's location in the tree.
inherited
createState() → State<GlassButton>
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