Skip to content

fix(ios): keep padding out of textContainerInset and write it on the label's own layout pass - #33

Open
edusperoni wants to merge 1 commit into
nativescript-community:masterfrom
edusperoni:fix/uilabel-padding-inset-source
Open

fix(ios): keep padding out of textContainerInset and write it on the label's own layout pass#33
edusperoni wants to merge 1 commit into
nativescript-community:masterfrom
edusperoni:fix/uilabel-padding-inset-source

Conversation

@edusperoni

Copy link
Copy Markdown

Fixes #29. Supersedes #32, which removes the wrong half of the duplication (see below).

Symptoms

On the UILabel path (non-selectable labels) padding is drawn once on the first render and twice after certain relayouts: recycled CollectionView cells (#29), or siblings shifting when a neighbouring label is restyled. With #32 applied the failure flips: the same labels draw with no padding until such a relayout happens, which is very visible on left-aligned text.

Root cause

There are two inset sources on the native NLabel, and only one of them is reliable.

  1. padding / borderThickness are written synchronously by @nativescript/core's Label setters (paddingInternalProperty, border*WidthProperty), which this plugin forwards to super when it is not using UITextView. NLabel.swift declares the same properties as TNSLabel, so core's setters land on it and textRect(forBounds:) sizes with them.
  2. textContainerInset is written by updateVerticalAlignment() from onLayout as padding + border (+ vertical-alignment correction).

Since 2.0.0 NLabel.drawText(in:) insets by all three, so whenever (2) has been written the padding is applied twice.

But (2) is only written on some layout passes. updateVerticalAlignment() returns early when !this.isLayoutValid. On iOS core defines isLayoutValid as "the force-layout flag is clear", and View.layout() (ui/core/view/index.ios.ts) clears that flag after onLayout returns. So on any pass the label requested itself, including its first one, onLayout sees isLayoutValid === false and textContainerInset stays at its previous value (zero for a fresh label). It only gets written when an ancestor drives the relayout and the label's bounds or measure spec change without the label having called requestLayout(). That is exactly the recycled-cell and sibling-shift cases.

So:

draw path inset written inset not written (label's own passes)
2.0.x (textContainerInset + padding + border) double correct
#32 / 1.x (textContainerInset only) correct zero padding

Change

  • updateTextContainerInset(): on the UILabel path the returned inset now carries only the vertical-alignment correction; padding and border are already applied natively from core's synchronous setters. The UITextView path is unchanged, since there textContainerInset is the real native property and the only inset source.
  • updateVerticalAlignment(applyVerticalTextAlignment, force): new force flag that bypasses the isLayoutValid guard. onLayout passes it, because the frame is already applied at that point and it is the only reliable place to write the inset. The guard still protects the early calls from onResumeNativeUpdates and the property setters, where bounds are zero.
  • onLayout now always ends with a forced updateVerticalAlignment (after updateAutoFontSize when auto font size is on), so the correction is also refreshed for auto-sized labels.
  • NLabel.swift is untouched: the 2.0.x draw path is correct once the JS side stops duplicating padding into textContainerInset.

Testing

Applied as a patch-package patch to @nativescript-community/ui-label@2.0.1 in a NativeScript 9.1 / Angular app that hit both symptoms (tab-set labels ellipsizing after a tap, left-aligned padded labels losing their inset with #32). Device verification of the patch is in progress; I'll report back here. No vertical-text-align usage in that app, so review of the top / bottom correction math would be appreciated from anyone relying on it.

…label's own layout pass

NLabel.drawText already insets by padding and borderThickness, which core sets synchronously. textContainerInset now only carries the vertical-alignment correction on the UILabel path, and onLayout forces the update because core's isLayoutValid is false for the whole pass a label requested itself.

Fixes nativescript-community#29
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.

Padding is applied doubled on RecyclerViews (like CollectionView)

1 participant