Switch Button
A switch: a setting that is on or off and takes effect at once, and the label it is the switch of.
import com.pantrixui.components.elements.switchbutton.PantrixSwitchButton
- One target. The track, the label and the supporting text are one target: a press on the words turns the switch too. The row takes the platform's touch target, small as the track is.
- Dragging the thumb. Let go past the middle of the track, the thumb turns the switch on, and short of the middle it turns it off; let go on the side it started from, it settles back and nothing is reported. The drag runs with the reading direction: in a right-to-left layout the on end is on the left.
- Platform. On Android the thumb grows from off to on, and further while it is held. On iOS, the desktop and the web it is one size; on iOS it is always white, there is a shadow under it, and the track has no edge.
- Error.
errorturns only the supporting text to the theme'sdangerrole, and a screen reader is told. The switch itself keeps its colours. - Form. The
PantrixSwitchButtonthat takes afieldgets its value, its error and its name from the form's field. The rule's message shows after the first change or on an attempt to submit the form, and takes the place of the supporting text. - Read-only and disabled. With a null
onCheckedChangethe switch is read-only: it takes no press, no drag and no focus, and still says its name and its state.enabled = falsedraws the switch in the disabled colours. - Its own colours.
SwitchColorstakes the colour of the track on and off, of the thumb on and off, and of the edge, each on its own; one that is left out stays the theme's role. A disabled switch is drawn in the theme's colours even when it is given colours. - Style.
SwitchStylegives the track's width and height, the thumb's size off, on and pressed, the edge's width and the thumb's shadow.labelStylegives the label's type; the track stands on its first line. - The switch at the end.
controlPosition = ControlPosition.Endputs the track at the end of the label, as a settings screen has it: given a width, the row has the track at its end, and the label wraps in the room left. - Motion. The thumb slides, and the track turns to the
primarycolour with it. In a theme with reduced motion both happen at once.
Examples
Label and supporting text
At its plainest: the state is read from checked, and onCheckedChange reports the value asked for. The track, the label and the supporting text are one target: a press on the words turns the switch too.
Drag the thumb: let go of it past the middle of the track and the switch turns. Let go short of the middle and it settles back, and nothing is reported.
var notifications by rememberSaveable { mutableStateOf(true) }
PantrixSwitchButton(
checked = notifications,
onCheckedChange = { notifications = it },
label = "Notifications",
supportingText = "Order updates and reminders",
tagKey = "notifications"
)
Without a label: in a row of the app's own
A row with the words at its start and the switch at its end is a row of the app's own: the words are a PantrixText of their own, and the switch has no label. contentDescription tells a screen reader the switch's name.
In this layout the words are no part of the target: what is pressed is the switch and the touch target kept around it.
var wifi by rememberSaveable { mutableStateOf(false) }
Row(modifier = Modifier.widthIn(max = 360.dp), verticalAlignment = Alignment.CenterVertically) {
PantrixText(text = "Wi-Fi", modifier = Modifier.weight(1f))
PantrixSwitchButton(
checked = wifi,
onCheckedChange = { wifi = it },
contentDescription = "Wi-Fi",
tagKey = "wifi"
)
}
Error
error turns the supporting text to the theme's danger role, and a screen reader is told the input is invalid. The switch itself keeps its colours: a switch is a setting, and an answer that can be wrong belongs to a checkbox.
Here the example works the error out itself: error is true while the switch is off. Turn the switch on: the text goes back to the colour it had.
var location by rememberSaveable { mutableStateOf(false) }
PantrixSwitchButton(
checked = location,
onCheckedChange = { location = it },
label = "Location",
supportingText = if (location) "Stores near you are shown" else "Stores cannot be searched while location is off",
error = !location,
tagKey = "location"
)
A setting bound to a form
The PantrixSwitchButton that takes a field is bound to a form's field: its value, its error and its name come from the field; checked and onCheckedChange are not given. The field's id is the automation key: the test tag is SwitchButton_two_step.
Press "Save" while two-step sign-in is off: the message of the Rules.mustBeTrue rule takes the place of the supporting text, and the focus goes to the switch. Turn the switch on and try again: the app's snackbar says the settings were saved.
val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
val form = rememberFormState()
PantrixSwitchButton(
field = form.field("two_step", initial = false, Rules.mustBeTrue("Your organisation requires this")),
label = "Two-step sign-in",
supportingText = "A code is sent by text message at every sign-in"
)
PantrixButton(
text = "Save",
onClick = {
scope.launch { form.submit { snackbars?.show(message = "Settings saved", tagKey = "saved") } }
},
form = form,
tagKey = "save_settings"
)
Disabled and read-only
enabled = false draws the switch in the disabled colours: it takes no press and no drag, and a screen reader is told it is disabled. The thumb's place still shows whether it is on or off.
With onCheckedChange = null the switch is read-only: it takes no press, no drag and no focus, its colours do not change, and it still says its name and its state.
PantrixSwitchButton(checked = true, onCheckedChange = {}, enabled = false, label = "Disabled", tagKey = "off")
PantrixSwitchButton(
checked = true,
onCheckedChange = null,
label = "Read-only",
supportingText = "Cannot be turned; it only shows its state",
tagKey = "read_only"
)
Its own colours
colors changes only the fields it is given: here the colours of the track and of the thumb while the switch is on. Turn the switch off: the track, the thumb and the edge are in the theme's colours. In between, the track and the thumb turn from one colour to the other as the thumb slides.
The app's purple is in none of the theme's roles; the colour of the thumb on such a track is the caller's to give as well. A disabled switch is drawn in the theme's colours even when it is given colours.
val own = ownColors()
var batterySaver by rememberSaveable { mutableStateOf(true) }
PantrixSwitchButton(
checked = batterySaver,
onCheckedChange = { batterySaver = it },
label = "Battery saver",
supportingText = "When on, the track's and the thumb's colours are given from outside; when off, they are the theme's",
colors = SwitchColors(checkedTrack = own.color, checkedThumb = own.onColor),
tagKey = "battery_saver"
)
Style
style changes the geometry of one switch. Only the fields that are given change; the rest comes from the theme's and the platform's style.
The first switch is given three fields of the iOS style and is drawn so on every platform: the thumb is always white (thumbAlwaysLight), with a shadow under it (thumbShadow), and the track has no edge when it is off (strokeWidth = 0.dp). The second is a larger track: the track's width and height and the thumb's size in its three states are given together. Its label is set by labelStyle in the theme's callout, in bold; the track stands on that type's first line.
var lightThumb by rememberSaveable { mutableStateOf(true) }
var largeTrack by rememberSaveable { mutableStateOf(false) }
PantrixSwitchButton(
checked = lightThumb,
onCheckedChange = { lightThumb = it },
label = "White thumb, with a shadow and no edge",
style = SwitchStyle(strokeWidth = 0.dp, thumbAlwaysLight = true, thumbShadow = 2.dp),
tagKey = "light_thumb"
)
PantrixSwitchButton(
checked = largeTrack,
onCheckedChange = { largeTrack = it },
label = "Large track",
style = SwitchStyle(
trackWidth = 64.dp,
trackHeight = 36.dp,
thumbSizeOff = 28.dp,
thumbSizeOn = 28.dp,
thumbSizePressed = 28.dp
),
tagKey = "large_track",
labelStyle = PantrixTheme.typography.callout.copy(fontWeight = FontWeight.Bold)
)
The switch at the end
A settings screen: the track at the end of the label (controlPosition = ControlPosition.End). The rows take the column's width (Modifier.fillMaxWidth()), the tracks stand one under another at the column's end, and a long label wraps in the room left.
var wifi by rememberSaveable { mutableStateOf(true) }
var saver by rememberSaveable { mutableStateOf(false) }
Column(Modifier.widthIn(max = 360.dp)) {
PantrixSwitchButton(
checked = wifi,
onCheckedChange = { wifi = it },
modifier = Modifier.fillMaxWidth(),
label = "Wi-Fi",
tagKey = "wifi_end",
controlPosition = ControlPosition.End
)
PantrixSwitchButton(
checked = saver,
onCheckedChange = { saver = it },
modifier = Modifier.fillMaxWidth(),
label = "Battery saver",
supportingText = "Cuts back refreshing in the background and some visual effects",
tagKey = "saver_end",
controlPosition = ControlPosition.End
)
}
API
checked
A switch: a setting that is on or off and takes effect at once, and the label it is the switch of.
| Parameter | Type | Default | What it is |
|---|---|---|---|
checked | Boolean | whether the switch is on. | |
onCheckedChange | ((Boolean) -> Unit)? | called with the value the user asks for, the opposite of checked. The switch changes nothing by itself: it is on when checked says so. Null makes it read-only. | |
modifier | Modifier | Modifier | the row's modifier. |
enabled | Boolean | true | whether the switch can be turned. One that cannot is drawn in the disabled colours and says so. |
label | String? | null | the text beside the track: part of the target, and the switch's name for a screen reader. |
supportingText | String? | null | help under the label, in a smaller type: the message, while error is true. |
error | Boolean | false | whether the value is wrong: the supporting text turns to the danger role, and a screen reader is told the input is invalid. |
style | SwitchStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform. |
colors | SwitchColors? | null | this switch's own colours: the ones it sets, with the theme's for the rest. A disabled switch keeps the theme's. |
contentDescription | String? | null | what a screen reader says for the switch: its name where it has no label, as in a row of the app's own that has the words elsewhere, or in place of the label. |
tagKey | String? | null | the switch's automation key: the row is SwitchButton_<tagKey>. A change is reported as a SwitchButton event that carries the new value, and never its label. |
interactionSource | MutableInteractionSource? | null | the switch's interactions, hoisted: its presses, its drags and its focus. It keeps a source of its own when this is null. |
labelStyle | TextStyle | PantrixTheme.typography.label | the type the label is set in: the theme's label unless given. The track stands on its first line at any size. A colour in it is the label's while the switch is enabled; a disabled switch writes it in the disabled colour. |
controlPosition | ControlPosition | ControlPosition.Start | where the track stands: before the label, or after it, as a settings screen has it. After it, the track is at the end of the width the row is given, Modifier.fillMaxWidth() lining it up with the others, or right after the label where the row is given none; the label wraps in what the track leaves. |
field
A switch bound to a form's field: its value, its error and its name come from field.
| Parameter | Type | Default | What it is |
|---|---|---|---|
field | FormField<Boolean> | the field the switch shows and changes. | |
modifier | Modifier | Modifier | the row's modifier. |
enabled | Boolean | true | whether the switch can be turned. |
label | String? | null | the text beside the track: part of the target, and the switch's name for a screen reader. |
supportingText | String? | null | help under the label, while the field has no error to show there. |
style | SwitchStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform. |
colors | SwitchColors? | null | this switch's own colours: the ones it sets, with the theme's for the rest. A disabled switch keeps the theme's. |
contentDescription | String? | null | what a screen reader says for the switch where it has no label, or in place of it. |
labelStyle | TextStyle | PantrixTheme.typography.label | the type the label is set in: the theme's label unless given. |
controlPosition | ControlPosition | ControlPosition.Start | where the track stands: before the label, or after it, as a settings screen has it. After it, the track is at the end of the width the row is given, Modifier.fillMaxWidth() lining it up with the others, or right after the label where the row is given none; the label wraps in what the track leaves. |
SwitchStyle
PantrixSwitchButton's track and its thumb: how large each is, the track's edge, and what the thumb looks like.
| Parameter | Type | Default | What it is |
|---|---|---|---|
trackWidth | Dp | Dp.Unspecified | The track's width, its edge included. |
trackHeight | Dp | Dp.Unspecified | The track's height, its edge included. The track's ends are as round as it is tall. |
thumbSizeOff | Dp | Dp.Unspecified | The thumb's width and height while the switch is off. |
thumbSizeOn | Dp | Dp.Unspecified | The thumb's width and height while the switch is on. |
thumbSizePressed | Dp | Dp.Unspecified | The thumb's width and height while it is pressed or dragged. |
strokeWidth | Dp | Dp.Unspecified | How thick the edge of a track that is off is. Zero draws none. |
thumbAlwaysLight | Boolean? | null | True keeps the thumb white whatever the theme and the state, as iOS has it. False draws it in the border colour when off and in the colour paired with the track's fill when on, as Material has it. Null is unspecified. |
thumbShadow | Dp | Dp.Unspecified | How far the thumb stands above the track: the size of the shadow under it. Zero draws none. |
SwitchColors
What PantrixSwitchButton is painted with, for a switch that does not take the theme's: a colour that is set is used, and one that is left out stays the theme's role.
| Parameter | Type | Default | What it is |
|---|---|---|---|
checkedTrack | Color | Color.Unspecified | The track's fill when the switch is on. The theme's primary. |
checkedThumb | Color | Color.Unspecified | The thumb when the switch is on: the colour that stands out on checkedTrack. The primary role's onColor, or white where the style keeps the thumb light. |
uncheckedTrack | Color | Color.Unspecified | The track's fill when the switch is off. A tint of the theme's borderStrong. |
uncheckedThumb | Color | Color.Unspecified | The thumb when the switch is off: the colour that stands out on uncheckedTrack. The theme's borderStrong, or white where the style keeps the thumb light. |
border | Color | Color.Unspecified | The edge of a track that is off, where the style draws one. The theme's borderStrong: a switch that is off is seen by its edge and its thumb. |
Accessibility
- Screen reader. One switch is read: its name is its label, and whether it is on or off is said in the theme's language. A switch with no label gets its name from
contentDescription.