Skip to content

iOS: opt-in iosReturnExitsEditing for multi-line TextArea (#4854)#4859

Merged
shai-almog merged 1 commit intomasterfrom
ios-return-exits-editing
May 3, 2026
Merged

iOS: opt-in iosReturnExitsEditing for multi-line TextArea (#4854)#4859
shai-almog merged 1 commit intomasterfrom
ios-return-exits-editing

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

@shai-almog shai-almog commented May 3, 2026

Summary

  • Adds a guarded client property iosReturnExitsEditing that makes the iOS keyboard's Return key act as Done on a multi-line TextArea -- exits editing (firing the Done listener) instead of inserting a newline. Mirrors the iOS Reminders task-title field.
  • While the flag is set, the keyboard's Return key is relabeled to Done (UIReturnKeyDone).
  • Default behavior is unchanged: the flag defaults to off, only takes effect on multi-line TextAreas, and only intercepts an exact "\n" replacement so pasted multi-line text is unaffected.

Closes #4854.

Why this shape

The reporter wants the Reminders-style growing text field where Return finishes editing rather than inserting a newline. Native iOS doesn't expose this as a built-in primitive -- Reminders implements it on a UITextView whose delegate intercepts \n in shouldChangeTextInRange:. We replicate that exactly, gated behind an opt-in client property so no existing layout changes behavior.

Touchpoints

  • IOSNative.java / IOSImplementation.java -- add boolean returnExitsEditing to editStringAt, populated from cmp.getClientProperty(\"iosReturnExitsEditing\") and forced false on single-line text fields.
  • IOSNative.m -- bridge function gets the new JAVA_BOOLEAN parameter; mangled name updated.
  • CodenameOne_GLViewController.m -- new global BOOL currentlyReturnExitsEditing (mirrors the existing currentlyEditingMaxLength pattern); set in editStringAtImpl; in the UITextView branch, forces returnKeyType = UIReturnKeyDone when the flag is set.
  • EAGLView.m / METALView.m -- textView:shouldChangeTextInRange:replacementText: intercepts a single \n replacement when the flag is set, calls existing keyboardDoneClicked (which fires stringEdit(YES, ...) -> Java fireDoneEvent), and returns NO to suppress the newline insertion.

Usage

TextArea ta = new TextArea(\"\", 3, 30);
ta.putClientProperty(\"iosReturnExitsEditing\", Boolean.TRUE);
ta.setDoneListener(e -> { /* Return / Done was tapped */ });

Test plan

  • Build iOS port: ./scripts/build-ios-port.sh -DskipTests
  • Sample app on device: multi-line TextArea with iosReturnExitsEditing=true -- pressing Return ends editing and the Done listener fires; long input wraps to multiple visible rows.
  • Same TextArea without the property -- Return still inserts \n (unchanged).
  • Single-line TextField regardless of property -- Return still resigns first responder (unchanged).
  • Pasting multi-line text into a TextArea with the property set -- newlines are preserved (interception is single-\n-only).
  • Toolbar Done/Next buttons (when iosHideToolbar not set) still work as before.

🤖 Generated with Claude Code

…Area (#4854)

Adds a guarded client property `iosReturnExitsEditing` that, when set on a
multi-line TextArea, makes the iOS keyboard's Return key act as Done -- it
exits editing (firing the Done listener) instead of inserting a newline.
This mirrors the iOS Reminders task-title field. The Return key is
relabeled to "Done" via UIReturnKeyDone while the flag is set.

The flag is wired through the existing editStringAt native call (mirroring
the blockCopyPaste/showToolbar pattern), gated to multi-line TextAreas only,
and defaults to off so existing behavior is unchanged. The interception
lives in textView:shouldChangeTextInRange:replacementText: in both EAGLView
and METALView and only fires for an exact "\n" replacement, leaving pasted
multi-line text untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 3, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 3, 2026

Compared 86 screenshots: 86 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 112 seconds

Build and Run Timing

Metric Duration
Simulator Boot 64000 ms
Simulator Boot (Run) 0 ms
App Install 13000 ms
App Launch 6000 ms
Test Execution 239000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1171.000 ms
Base64 CN1 encode 1279.000 ms
Base64 encode ratio (CN1/native) 1.092x (9.2% slower)
Base64 native decode 696.000 ms
Base64 CN1 decode 947.000 ms
Base64 decode ratio (CN1/native) 1.361x (36.1% slower)
Base64 SIMD encode 509.000 ms
Base64 encode ratio (SIMD/native) 0.435x (56.5% faster)
Base64 encode ratio (SIMD/CN1) 0.398x (60.2% faster)
Base64 SIMD decode 411.000 ms
Base64 decode ratio (SIMD/native) 0.591x (40.9% faster)
Base64 decode ratio (SIMD/CN1) 0.434x (56.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 58.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.155x (84.5% faster)
Image applyMask (SIMD off) 132.000 ms
Image applyMask (SIMD on) 60.000 ms
Image applyMask ratio (SIMD on/off) 0.455x (54.5% faster)
Image modifyAlpha (SIMD off) 121.000 ms
Image modifyAlpha (SIMD on) 59.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.488x (51.2% faster)
Image modifyAlpha removeColor (SIMD off) 157.000 ms
Image modifyAlpha removeColor (SIMD on) 79.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.503x (49.7% faster)
Image PNG encode (SIMD off) 934.000 ms
Image PNG encode (SIMD on) 807.000 ms
Image PNG encode ratio (SIMD on/off) 0.864x (13.6% faster)
Image JPEG encode 456.000 ms

@shai-almog shai-almog merged commit 2804711 into master May 3, 2026
16 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.

Make TextField behavior closer to iPhone native by allowing Return to exit editing instead of inserting a newline

1 participant