@@ -31,6 +31,8 @@ class SwitchChangeHandlerImpl extends NSObject {
3131export class Switch extends SwitchBase {
3232 nativeViewProtected : UISwitch ;
3333 private _handler : NSObject ;
34+ // Defer color updates while iOS 26+ "glass" toggle animation runs
35+ private _toggleColorTimer : NodeJS . Timeout | null = null ;
3436
3537 constructor ( ) {
3638 super ( ) ;
@@ -49,20 +51,57 @@ export class Switch extends SwitchBase {
4951
5052 public disposeNativeView ( ) {
5153 this . _handler = null ;
54+ if ( this . _toggleColorTimer ) {
55+ clearTimeout ( this . _toggleColorTimer ) ;
56+ this . _toggleColorTimer = null ;
57+ }
5258 super . disposeNativeView ( ) ;
5359 }
5460
5561 private setNativeBackgroundColor ( value : UIColor | Color ) {
62+ const native = this . nativeViewProtected ;
5663 if ( value ) {
57- this . nativeViewProtected . onTintColor = value instanceof Color ? value . ios : value ;
58- this . nativeViewProtected . tintColor = value instanceof Color ? value . ios : value ;
59- this . nativeViewProtected . backgroundColor = value instanceof Color ? value . ios : value ;
60- this . nativeViewProtected . layer . cornerRadius = this . nativeViewProtected . frame . size . height / 2 ;
64+ const nativeValue = value instanceof Color ? value . ios : value ;
65+ // Keep the legacy behavior for on/off colors
66+ native . onTintColor = nativeValue ;
67+ native . tintColor = nativeValue ;
68+ native . backgroundColor = nativeValue ;
69+
70+ // Since iOS 16+ the control no longer clips its background by default.
71+ // Ensure the track-shaped background doesn't bleed outside the control bounds.
72+ if ( SDK_VERSION >= 16 ) {
73+ native . clipsToBounds = true ;
74+ native . layer . masksToBounds = true ;
75+ }
76+
77+ // Corner radius must be based on the final laid out size; use bounds first,
78+ // then fall back to frame. If size isn't known yet, update on the next tick.
79+ const height = native . bounds ?. size ?. height || native . frame ?. size ?. height || 0 ;
80+ if ( height > 0 ) {
81+ native . layer . cornerRadius = height / 2 ;
82+ } else {
83+ // Defer until after layout
84+ setTimeout ( ( ) => {
85+ const n = this . nativeViewProtected ;
86+ if ( ! n ) {
87+ return ;
88+ }
89+ const h = n . bounds ?. size ?. height || n . frame ?. size ?. height || 0 ;
90+ if ( h > 0 ) {
91+ n . layer . cornerRadius = h / 2 ;
92+ }
93+ } , 0 ) ;
94+ }
6195 } else {
62- this . nativeViewProtected . onTintColor = null ;
63- this . nativeViewProtected . tintColor = null ;
64- this . nativeViewProtected . backgroundColor = null ;
65- this . nativeViewProtected . layer . cornerRadius = 0 ;
96+ native . onTintColor = null ;
97+ native . tintColor = null ;
98+ native . backgroundColor = null ;
99+ native . layer . cornerRadius = 0 ;
100+ if ( SDK_VERSION >= 16 ) {
101+ // Restore default clipping behavior
102+ native . clipsToBounds = false ;
103+ native . layer . masksToBounds = false ;
104+ }
66105 }
67106 }
68107
@@ -74,10 +113,23 @@ export class Switch extends SwitchBase {
74113 super . _onCheckedPropertyChanged ( newValue ) ;
75114
76115 if ( this . offBackgroundColor ) {
77- if ( ! newValue ) {
78- this . setNativeBackgroundColor ( this . offBackgroundColor ) ;
116+ const nextColor = ! newValue ? this . offBackgroundColor : this . backgroundColor instanceof Color ? this . backgroundColor : new Color ( this . backgroundColor ) ;
117+
118+ // On iOS 26+, coordinate with the system's switch animation:
119+ // delay applying track color until the toggle animation finishes to avoid a janky mid-animation recolor.
120+ if ( SDK_VERSION >= 26 ) {
121+ if ( this . _toggleColorTimer ) {
122+ clearTimeout ( this . _toggleColorTimer ) ;
123+ }
124+ this . _toggleColorTimer = setTimeout ( ( ) => {
125+ const ANIMATION_DELAY_MS = 0.26 ; // approx. system toggle duration
126+ UIView . animateWithDurationAnimations ( ANIMATION_DELAY_MS , ( ) => {
127+ this . _toggleColorTimer = null ;
128+ this . setNativeBackgroundColor ( nextColor ) ;
129+ } ) ;
130+ } , 0 ) ;
79131 } else {
80- this . setNativeBackgroundColor ( this . backgroundColor instanceof Color ? this . backgroundColor : new Color ( this . backgroundColor ) ) ;
132+ this . setNativeBackgroundColor ( nextColor ) ;
81133 }
82134 }
83135 }
0 commit comments