GlassSegmentedControl class

A glass morphism segmented control following Apple's design patterns.

GlassSegmentedControl provides a sophisticated segmented control with an animated glass indicator, jelly physics, and smooth transitions between segments. It matches iOS's UISegmentedControl appearance and behavior.

Key Features

  • Animated Glass Indicator: Smoothly animates between segments
  • Jelly Physics: Organic squash and stretch effects during movement
  • Drag Support: Swipe between segments with velocity-based snapping
  • Sharp Text: Selected text stays sharp above the glass
  • Flexible Sizing: Automatically sizes segments evenly
  • Customizable Appearance: Full control over colors, sizes, and effects

Performance Note

When placing inside glass containers (GlassCard) with blur, use one of these approaches for best performance:

  • Set parent container to quality: GlassQuality.premium (no BackdropFilter)
  • Or set parent settings to blur: 0 (skips BackdropFilter)
  • Or place outside glass containers (like bottom bars)

Standard quality glass containers with blur may show minor flicker during indicator animations due to BackdropFilter recomposition.

Usage

Basic Usage

int selectedIndex = 0;

GlassSegmentedControl(
  segments: const [
    GlassSegment(label: 'Daily'),
    GlassSegment(label: 'Weekly'),
    GlassSegment(label: 'Monthly'),
  ],
  selectedIndex: selectedIndex,
  onSegmentSelected: (index) {
    setState(() => selectedIndex = index);
  },
)

Within LiquidGlassLayer (Grouped Mode)

AdaptiveLiquidGlassLayer(
  settings: LiquidGlassSettings(
    thickness: 30,
    blur: 3,
    refractiveIndex: 1.59,
  ),
  child: Column(
    children: [
      GlassSegmentedControl(
        segments: const [
          GlassSegment(label: 'One'),
          GlassSegment(label: 'Two'),
          GlassSegment(label: 'Three'),
        ],
        selectedIndex: _selectedIndex,
        onSegmentSelected: (index) {
          setState(() => _selectedIndex = index);
        },
      ),
    ],
  ),
)

Standalone Mode

GlassSegmentedControl(
  segments: const [
    GlassSegment(label: 'Option A'),
    GlassSegment(label: 'Option B'),
  ],
  selectedIndex: _selectedIndex,
  onSegmentSelected: (index) {
    setState(() => _selectedIndex = index);
  },
  useOwnLayer: true,
  settings: LiquidGlassSettings(
    thickness: 30,
    blur: 3,
  ),
)

Icons and labels

GlassSegmentedControl(
  segments: const [
    GlassSegment(icon: Icon(Icons.photo),     label: 'Photos'),
    GlassSegment(icon: Icon(Icons.videocam),  label: 'Videos'),
    GlassSegment(icon: Icon(Icons.music_note),label: 'Music'),
  ],
  selectedIndex: _selectedIndex,
  onSegmentSelected: (index) =>
      setState(() => _selectedIndex = index),
  height: 56,
)

Custom Styling

GlassSegmentedControl(
  segments: const [
    GlassSegment(label: 'Small'),
    GlassSegment(label: 'Medium'),
    GlassSegment(label: 'Large'),
  ],
  selectedIndex: _selectedIndex,
  onSegmentSelected: (index) =>
      setState(() => _selectedIndex = index),
  height: 36,
  borderRadius: 18,
  selectedTextStyle: TextStyle(
    fontSize: 14,
    fontWeight: FontWeight.w600,
    color: CupertinoColors.white,
  ),
  unselectedTextStyle: TextStyle(
    fontSize: 14,
    fontWeight: FontWeight.w500,
    color: CupertinoColors.white.withOpacity(0.6),
  ),
)
Inheritance

Constructors

GlassSegmentedControl({required List<GlassSegment> segments, required int selectedIndex, required ValueChanged<int> onSegmentSelected, Key? key, double height = GlassDefaults.heightControl, double borderRadius = GlassDefaults.borderRadius, EdgeInsetsGeometry padding = const EdgeInsets.all(2), TextStyle? selectedTextStyle, TextStyle? unselectedTextStyle, Color? backgroundColor, Color? indicatorColor, LiquidGlassSettings? indicatorSettings, double indicatorPinchStrength = 0.4, EdgeInsetsGeometry indicatorExpansion = const EdgeInsets.symmetric(horizontal: 12, vertical: 8), LiquidGlassSettings? settings, bool useOwnLayer = false, GlassQuality? quality, GlobalKey<State<StatefulWidget>>? backgroundKey, GlassInteractionBehavior interactionBehavior = GlassInteractionBehavior.full, Color? glowColor, double glowRadius = 1.5, bool isScrollable = false, double iconSize = 24.0, EdgeInsetsGeometry labelPadding = const EdgeInsets.symmetric(horizontal: 16), Color? selectedIconColor, Color? unselectedIconColor, MaskingQuality maskingQuality = MaskingQuality.high, DividerSettings? dividerSettings, List<BoxShadow>? indicatorShadow})
Creates a fixed-width glass segmented control (iOS UISegmentedControl).
const
GlassSegmentedControl.scrollable({required List<GlassSegment> segments, required int selectedIndex, required ValueChanged<int> onSegmentSelected, Key? key, double height = 44.0, double borderRadius = GlassDefaults.borderRadius, EdgeInsetsGeometry padding = const EdgeInsets.all(2), TextStyle? selectedTextStyle, TextStyle? unselectedTextStyle, Color? backgroundColor, Color? indicatorColor, LiquidGlassSettings? indicatorSettings, double indicatorPinchStrength = 0.4, EdgeInsetsGeometry indicatorExpansion = const EdgeInsets.symmetric(horizontal: 12, vertical: 8), LiquidGlassSettings? settings, bool useOwnLayer = false, GlassQuality? quality, GlobalKey<State<StatefulWidget>>? backgroundKey, double iconSize = 24.0, EdgeInsetsGeometry labelPadding = const EdgeInsets.symmetric(horizontal: 16), Color? selectedIconColor, Color? unselectedIconColor, MaskingQuality maskingQuality = MaskingQuality.high, DividerSettings? dividerSettings, List<BoxShadow>? indicatorShadow})
Creates a scrollable glass segmented control that 100% mimics GlassTabBar(isScrollable: true) from the original API.
const

Properties

backgroundColor Color?
Background color of the segmented control.
final
backgroundKey GlobalKey<State<StatefulWidget>>?
Optional background key for Skia/Web refraction.
final
borderRadius double
Border radius of the segmented control.
final
dividerSettings DividerSettings?
Optional divider settings between segments. Scrollable mode only.
final
glowColor Color?
Colour of the press/drag glow on the indicator pill.
final
glowRadius double
Spread radius of the glow relative to the indicator's shorter dimension.
final
hashCode int
The hash code for this object.
no setterinherited
height double
Height of the segmented control.
final
iconSize double
Icon size in logical pixels. Used in scrollable mode only. Defaults to 24.0 — matching GlassTabBar.
final
indicatorColor Color?
Color of the indicator when not being dragged.
final
indicatorExpansion EdgeInsetsGeometry
Expansion padding applied to the active indicator pill during interaction.
final
indicatorPinchStrength double
Maximum concave lens pinch strength for the sliding indicator pill.
final
indicatorSettings LiquidGlassSettings?
Glass settings for the draggable indicator.
final
indicatorShadow List<BoxShadow>?
Optional box shadows on the pill indicator. Scrollable mode only.
final
interactionBehavior GlassInteractionBehavior
Controls which iOS 26 interaction effects are active on the indicator.
final
isScrollable bool
Whether this control scrolls horizontally.
final
key Key?
Controls how one widget replaces another widget in the tree.
finalinherited
labelPadding EdgeInsetsGeometry
Horizontal padding inside each tab label cell. Scrollable mode only.
final
maskingQuality MaskingQuality
Masking quality for the dual-layer icon rendering. Scrollable mode only.
final
onSegmentSelected ValueChanged<int>
Called when a segment is selected.
final
padding EdgeInsetsGeometry
Padding around the indicator inside the background.
final
quality GlassQuality?
Rendering quality for the glass effect.
final
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
segments List<GlassSegment>
List of segments to display.
final
selectedIconColor Color?
Icon color for the selected segment. Scrollable mode only. Defaults to the primary label color.
final
selectedIndex int
Index of the currently selected segment.
final
selectedTextStyle TextStyle?
Text style for the selected segment.
final
settings LiquidGlassSettings?
Glass effect settings (only used when useOwnLayer is true).
final
unselectedIconColor Color?
Icon color for unselected segments. Scrollable mode only. Defaults to the secondary label color.
final
unselectedTextStyle TextStyle?
Text style for unselected segments.
final
useOwnLayer bool
Whether to create its own layer or use grouped glass.
final

Methods

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