Hue slider
v0.0.10
mix mishka.ui.gen.mob hue_slider
The Mob Hue Slider is the native iOS and Android version of the headless Hue Slider in Mishka Chelekom. It draws a rainbow track and turns a touch or drag on it into a hue from 0 to 360 degrees. Mob renders it with Jetpack Compose on Android and SwiftUI on iOS.
Overview of the Mob Hue Slider component for iOS and Android
The hue slider draws a rainbow on a canvas as a run of filled bands, one band for every two units of width, and lays a marker over the current hue. The track is 300 units wide and 16 units high by default.
The strip is the control, and no native slider sits under it. A touch on the strip sends your screen a {:drag, tag, payload} message with the touch position, and hue_at/2 converts that position to a hue. The phase field reports began on touch-down, dragging while the finger moves and ended on release. A tap therefore sets the hue.
The screen owns the state. The slider draws the value you pass, so you assign the new hue in handle_info/2 and the marker moves. Set label for a caption above the track and show_value for a readout such as 210°. With both, the label sits on the left and the readout on the right.
Generate the hue slider component
Run this from your Mob app's root to add the component to lib/<app>/components/:
mix mishka.ui.gen.mob hue_sliderThe generator registers the tag, so you can use it in ~MOB markup. It also copies the shared Color and Event helper modules. The examples on this page use the mishka_ prefix of the showcase app (--module-prefix mishka_), so the tag is <MishkaHueSlider>. Without a prefix, the tag is <HueSlider>.
Hue slider with a drawn spectrum
The rainbow is 150 canvas bands, so the track is a real gradient. This example sets label and show_value, and converts the touch position with hue_at/2 in handle_info/2. The colored box under the slider in the screenshot belongs to the showcase page and is not part of the component.
Hue slider with a drawn spectrum
<MishkaHueSlider value={@hue} label="Hue" show_value={true} on_change={:hue} />
# The strip IS the control, so the event carries a touch POSITION, not a
# value. hue_at/2 inverts the marker, so the colour under the finger is
# the colour selected. Matching {:change, ...} instead renders a perfect
# strip that does nothing.
def handle_info({:drag, :hue, %{x: x}}, socket) do
{:noreply, Mob.Socket.assign(socket, :hue, MishkaHueSlider.hue_at(x))}
endHelper functions
The module exports two helpers. Call them from your screen.
| Function | Description |
|---|---|
hue_at(x, width \\ 300) | Converts a touch x position, in canvas units from the left edge of the strip, to a hue. It is the inverse of the marker, so the finger and the marker agree. Pass the same width the strip is drawn at. |
spectrum(width, height, hue) | Returns the draw ops for the rainbow strip with a marker at the given hue, as a list of plain maps. |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | number, 0 to 360 | 0 | The current hue in degrees. A value outside the range wraps, and 360 stays at the far end of the strip. |
width | number | 300 | Track width in logical units. |
height | number | 16 | Track height in logical units. |
label | string | nil | Caption above the track. |
show_value | boolean | false | Shows a readout such as 210°. |
on_change | event tag | None | Sends {:drag, tag, payload} with a touch position. Convert it with hue_at/2. |
id | string | None | A native test tag for the strip. A canvas has no text that a test can find it by. |
Events
on_change sends {:drag, tag, %{x:, y:, dx:, dy:, phase:}} to the screen that rendered the slider, and the screen handles it in handle_info/2. The payload holds a touch position, so use hue_at/2 to get a hue. The phase field reports began on touch-down, dragging while the finger moves and ended on release. The dx and dy fields in the payload differ between iOS and Android, so build on x and y only.
def handle_info({:drag, :hue, %{x: x}}, socket) do
{:noreply, Mob.Socket.assign(socket, :hue, MishkaHueSlider.hue_at(x))}
end
def handle_info(_msg, socket), do: {:noreply, socket}Differences from the web component
The Mob version leaves these parts of the web slider out or changes them:
- The track is bands drawn on a canvas, where the web version puts a CSS
linear-gradienton the track. on_commitis not ported, because the Mob bridge has no release event.stepandlarge_step(keyboard nudging) are not ported.nameandformare not ported. Theidprop is a native test tag, not a DOM id.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
value
|
number
|
0
| — | No | Current hue in degrees. Out-of-range values wrap; 360 stays at the far end. |
width
|
number
|
300
| — | No | Track width in logical units. |
height
|
number
|
16
| — | No | Track height. |
show_value
|
boolean
|
false
| — | No | Render a `210°` readout. |
label
|
string
| — | — | No | Caption above the track. |
on_change
|
event tag (atom)
| — | — | No | `{:drag, tag, %{x:, y:, dx:, dy:, phase:}}` — a touch POSITION, not a value. Convert with `hue_at/2`. |
id
|
string
| — | — | No | A native testTag. A canvas has no text to find it by. |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
hue_slider
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.mob hue_slider