Segmented control
GlassSegmentedControl picks one of two to five options. The selected segment lifts into a clear glass drop you can slide to another segment.
GlassSegmentedControl · kGlassSegmentTrack · kGlassSegmentDropGrow · kGlassSegmentDropWiden · Source
GlassSegmentedControl is iOS 26's segmented control. The track is a flat translucent fill, and the
selected segment sits on a white capsule. Press the selection and it lifts into a clear glass drop
that stands out of the track; slide it along and let go over another segment to select that one.
Tapping a segment selects it directly.
The track and the capsule are paint, not glass, so at rest the control costs nothing. The drop exists only while it is held.
When to use
- Two to five mutually exclusive views or filters: Day / Week / Month, List / Grid / Map.
- Not for navigation between the main sections of an app: that is a tab bar.
- Not for one on/off option: that is a switch.
- Not for more than five options, or long labels. It asserts at least two segments.
Usage
SizedBox(
width: 280,
child: GlassSegmentedControl(
segments: const <Widget>[Text('Day'), Text('Week'), Text('Month')],
selectedIndex: _range,
onSelected: (int i) => setState(() => _range = i),
),
)
The control is 32 px tall (44 px with its tap area) and takes the width of its parent, divided evenly between segments. It needs a bounded width.
Label colours
The control lives in the content layer, so it does not pick a label colour for the unselected
segments: they use the ambient DefaultTextStyle and IconTheme. Inside a Card
that is already the card's legible colour. Elsewhere, set it yourself with DefaultTextStyle.merge.
The selected segment's label is picked for you, black on a light thumbColor and white on a
dark one.
Accessibility
Each segment is a button for a screen reader, with the selected one marked as selected. Text
segments read their text. For icon segments, wrap each icon in Semantics(label: ...) or use
Icon(..., semanticLabel: ...).
Code
import 'package:flutter/material.dart';
import 'package:g1455/g1455.dart';
/// A calendar header: a range picker on a glass card, and what it selects.
/// Assumes a GlassHost above the navigator (MaterialApp.builder).
class RangePicker extends StatefulWidget {
const RangePicker({super.key});
@override
State<RangePicker> createState() => _RangePickerState();
}
class _RangePickerState extends State<RangePicker> {
static const List<String> _ranges = <String>['Day', 'Week', 'Month', 'Year'];
int _range = 1;
@override
Widget build(BuildContext context) => SizedBox(
width: 360,
child: GlassCard(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
// Unselected labels take this style; the card has already set the colour.
DefaultTextStyle.merge(
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
child: GlassSegmentedControl(
segments: <Widget>[for (final String r in _ranges) Text(r)],
selectedIndex: _range,
onSelected: (int i) => setState(() => _range = i),
),
),
const SizedBox(height: 16),
Text(
'This ${_ranges[_range].toLowerCase()}',
style: const TextStyle(fontSize: 17, fontWeight: FontWeight.w600),
),
],
),
),
);
}
/// Icon segments with labels for screen readers, on a dark thumb.
Widget layoutPicker(int index, ValueChanged<int> onSelected) => SizedBox(
width: 200,
child: GlassSegmentedControl(
segments: const <Widget>[
Icon(Icons.list, semanticLabel: 'List'),
Icon(Icons.grid_view, semanticLabel: 'Grid'),
Icon(Icons.map, semanticLabel: 'Map'),
],
selectedIndex: index,
onSelected: onSelected,
thumbColor: const Color(0xFF636366),
),
);API
| Parameter | Type | Default | Description |
|---|---|---|---|
segments |
List<Widget> |
required | One widget per segment, usually a Text or an Icon. At least 2. |
selectedIndex |
int |
required | The selected segment. |
onSelected |
ValueChanged<int>? |
required | Called with the new index. Null disables the control (half opacity). |
trackColor |
Color |
kGlassSegmentTrack |
The track's fill. |
thumbColor |
Color |
Color(0xFFFFFFFF) |
The capsule under the selected segment at rest. |
key |
Key? |
null |
Constants
| Name | Value | Description |
|---|---|---|
kGlassSegmentTrack |
Color.fromRGBO(118, 118, 128, 0.12) |
The default track fill (iOS's tertiary system fill). |
kGlassSegmentDropGrow |
Size(12, 8) |
How much larger the held drop is than the capsule, per side. |
kGlassSegmentDropWiden |
2.9 |
How many px of the surroundings the drop pulls in (a slight zoom-out). |