fix(perry-ui-ios): #1107 partial-alpha text invisible on iOS 26#1109
Merged
Conversation
UILabel.setTextColor: and UIButton.setTitleColor:forState: with a UIColor whose alpha < 1.0 render zero glyphs on iOS 26 device (alpha == 1.0 paints fine, iOS 17 simulator is unaffected, and the AttributedText widget's NSAttributedString-with-NSColor path renders correctly). Likely an iOS 26 / Liquid Glass text renderer regression. Workaround: for alpha < 1.0, mirror AttributedText's working code path on the plain Text/Button receivers — build an NSAttributedString with NSFont + NSColor attrs (pulled from the label's current font / the button's titleLabel.font) and apply it via setAttributedText: or setAttributedTitle:forState:UIControlStateNormal. The plain setTextColor:/setTitleColor: call is still issued so any setText: / setTitle: clobber later retains a reasonable fallback color. For alpha == 1.0 we leave the simple path alone (and explicitly clear any prior attributedText/attributedTitle) to avoid disturbing intrinsic-content sizing on the non-buggy iOS 17 path. Files: - crates/perry-ui-ios/src/widgets/text.rs - crates/perry-ui-ios/src/widgets/button.rs No version bump or changelog change.
proggeramlug
added a commit
that referenced
this pull request
May 19, 2026
…+ nested stack bg (#1127) * fix(perry-ui-ios): finish #1107 — iOS 26 device rendering of Buttons + nested stack bg PR #1109 shipped a partial fix for #1107 (partial-alpha NSColor renders zero glyphs on iOS 26 device) but three regressions / blind spots remained, all reproduced on physical iPhone running iOS 26.5: 1. Text widgets with `textSetColor(α < 1.0)` (e.g. Material's 87% black) still rendered nothing. #1109's `apply_label_color_via_attributed` reused the label's borrowed `view.font` pointer and the un-retained `initWithString:attributes:` result; the working AttributedText path builds a fresh `[UIFont systemFontOfSize:]` and retains the result. This commit mirrors that exact pattern. 2. Bare `Button("Mitmachen", cb)` + `widgetSetBackgroundColor(BRAND_RED)` rendered invisible. `buttonWithType:UIButtonTypeSystem` on iOS 26 routes through the Liquid Glass renderer, which overrides explicit `setTitleColor:` / `setBackgroundColor:` with the system tint. Switch to `UIButtonTypeCustom` (and seed `[UIColor labelColor]` as the default title color so a bare button with no explicit color is still visible). Also drop the `setAttributedTitle:nil` cleanup branch from #1109 — on iOS 26 it nukes the button's plain-title rendering along with the attributed state, leaving even α==1.0 buttons blank. 3. `widgetSetBackgroundColor` on a NESTED `UIStackView` painted transparent. `UIStackView.backgroundColor` is documented iOS 14+ but the property doesn't drive painting on inner stacks under iOS 26's compositor. The CALayer's own `backgroundColor` (CGColor) does paint reliably, so set both — view-level for non-buggy paths (root stack, iOS 17 sim) and layer-level as the belt-and-suspenders fix. Verified on iPhone running iOS 26.5: bisect of the Wishare Onboarding screen (TEXT_PRIMARY α=0.87 labels, BRAND_RED-bg `Mitmachen` button, white-bg nested card VStack) now renders all three widget classes. Follow-up issue #1122 tracks the broader audit of iOS 26 regressions. * style(perry-ui-ios): cargo fmt — drop stray blank line in widgets/mod.rs Lint job on PR #1127 failed on `cargo fmt --check`. Single extraneous blank line between `set_background_color` and `gradient_bg_class`.
4 tasks
proggeramlug
added a commit
that referenced
this pull request
May 21, 2026
…utton (#1284) PR #1127 added a CALayer.backgroundColor fallback for UIStackView to work around nested-stack transparency on iOS 26 device. UIButton has the same class of bug — Liquid Glass renderer can override setBackgroundColor: on certain button-type/configuration combinations even after #1127 forced UIButtonTypeCustom. Apply the same belt-and-suspenders fallback to UIButton so the CGColor lands on the layer directly regardless of UIKit-side interception. No behavior change for ordinary UIViews (setBackgroundColor: already updates layer.backgroundColor on those). Also rewrites the function's doc comment — it previously described an "inserting a UIView pinned to stack bounds" fallback that the actual implementation never did (we always set layer.backgroundColor with CGColor). Documents both currently-known iOS 26 cases (UIStackView, UIButton) and the rationale. Closes #1122 pending on-device retest. Native side has now layered #1109 (attributed-text for partial-alpha labels), #1127 (UIButtonTypeCustom + UIStackView layer fallback), and this PR (UIButton layer fallback). Underlying TS-compiler bug #1129 — which silently produced NaN/ undefined when the consumer app imported color object literals from another module, masking all native-side fixes — was closed by #1281 (baaeb44).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1107.
Root cause
On iOS 26 device,
UILabel.setTextColor:andUIButton.setTitleColor:forState:with aUIColorwhose alpha < 1.0 render zero glyphs. Reporter confirmed:AttributedTextwidget's path — UIColor underNSColor/NSForegroundColorAttributeNameinside an NSAttributedString applied viasetAttributedText:— renders correctly with sub-1.0 alphaLooks like an iOS 26 / Liquid Glass text renderer regression: the plain
textColor/titleColorpaths are silently dropped (or rasterised invisibly) when the color isn't fully opaque, while the attributed-text path goes through a different renderer that still honors partial alpha.Fix
In
crates/perry-ui-ios/src/widgets/text.rs::set_color(UILabel) andcrates/perry-ui-ios/src/widgets/button.rs::set_text_color(UIButton): foralpha < 1.0, mirrorAttributedText::append's known-working code path on the plain widget by also settingattributedText/attributedTitle:forState::text/titleForState:UIControlStateNormalfont(from the label orbutton.titleLabel.font)NSAttributedStringwithNSFont+NSColorattrs (matchingattributed_text.rsline-for-line on the keys)setAttributedText:/setAttributedTitle:forState:UIControlStateNormalsetTextColor:/setTitleColor:is still issued first, so any latersetText:/setTitle:clobber (which discards the attributed buffer) retains a reasonable solid-color fallback. Foralpha == 1.0we explicitly clear any prior attributedText/attributedTitle so the plain path takes over, avoiding disturbing intrinsic-content sizing on the unaffected iOS 17 path.Critically, the NSFont attr is always emitted — the reporter's "Routing
set_colorthroughsetAttributedText:with NSColor in attributes dict … Zero-glyph" bisection-step likely didn't include NSFont, and on iOS 26 it appears NSFont is required for sub-1.0 alpha to render.Files touched
crates/perry-ui-ios/src/widgets/text.rscrates/perry-ui-ios/src/widgets/button.rsNo TS / HIR / codegen / shim changes.
Test plan
The agent doesn't have iOS 26.5 device access. Reporter should validate:
Button(...)title withtextSetColor(btn, 0, 0, 0, 0.87)— expect 87%-black glyphs.Text+textSetColorwith both alpha == 1.0 and alpha == 0.87 still render.AttributedTextwidget still works (untouched code path; smoke test only).If the alpha < 1.0 cases still come out blank on device, the next hypothesis is that NSColor (the iOS legacy key) needs to be
NSForegroundColorAttributeNameliteral (@"NSColor"resolves to the same symbol but if Apple changed it on iOS 26, we'd want to look upkCTForegroundColorAttributeNamefrom CoreText instead). Easy follow-up if validation fails.No version bump or changelog change — maintainer will fold those in at merge.