Skip to content

Render Slider and TextField#13

Merged
colemancda merged 8 commits into
feature/form-controlsfrom
feature/form-controls-2
Jul 22, 2026
Merged

Render Slider and TextField#13
colemancda merged 8 commits into
feature/form-controlsfrom
feature/form-controls-2

Conversation

@colemancda

Copy link
Copy Markdown
Member

Second half of the form controls work, stacked on #12 — review that first. Retarget to master once #12 merges.

Important

Depends on PureSwift/Android#47, which adds constructors to the SeekBar and EditText bindings. Neither could be instantiated before it. Developed against that branch via a local dependency mirror; needs #47 merged before this builds from a clean checkout.

Slider

Rendered as a SeekBar, bound to its Double within its range.

SeekBar reports whole numbers while Slider works in a floating point range, so the bar is divided into steps — matching the slider's own step when it has one, so the thumb lands exactly on each value, and a fixed fine-grained scale when continuous.

TextField

Rendered as an EditText, bound to its String, with the label as the hint.

The update path only writes back when the text actually differs. Writing unconditionally would reset the cursor to the start on every keystroke, since the watcher has already applied the user's edit by the time the reconciler runs.

JNI bridges

Two new bridges, SeekBarOnSeekBarChangeListener and EditTextTextWatcher.

Both differ from ViewOnClickListener in one respect worth noting: the Kotlin side collapses the interface's callbacks into a single external method and drops the view argument, rather than declaring the interface methods themselves external. The native symbol is derived from the Swift signature, so a Kotlin method that passes extra leading arguments shifts everything — the first version of the slider read the SeekBar pointer as the progress value and reported -8652525%. Forwarding only what Swift declares keeps the signatures aligned.

TextWatcher also has no Swift binding at all, so EditTextTextWatcher registers itself on the field from Kotlin. SeekBarOnSeekBarChangeListener does the same for symmetry.

Layout

The determinate progress track and the seek bar both span the stack rather than hugging their content. A seek bar at its intrinsic width collapses to just the thumb and cannot be dragged at all; the horizontal progress track is similarly meaningless. The indeterminate spinner keeps its natural size.

Not included

Stepper and Picker. Stepper has no definition in the vendored SwiftUI layer at all, so it needs new API surface rather than just a renderer. Picker renders through _PickerContainer, whose generic selection value needs mapping to and from adapter indices — enough work to be worth its own change.

Verification

On the emulator:

  • The slider drags and drives its bound @State (50% → 86%), with the label tracking it.
  • Typing into the text field updates its binding per keystroke, with the cursor staying put ("Coleman" → "Hello, Coleman").
  • Toggle and both progress views still behave as in Render ProgressView and Toggle #12.

@colemancda
colemancda merged commit 7573749 into feature/form-controls Jul 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant