Skip to content

Commit fd43bcc

Browse files
fix(ios): add Auto Layout constraints to RNNReactButtonView on iOS 26
On iOS 26 the Liquid Glass navigation bar wraps custom-view bar button items in several internal layout containers. Without explicit size constraints the wrapper views can collapse to zero height after a pop → tab-switch → tab-switch → push cycle, making the React button invisible. - Guard all new logic behind @available(iOS 26.0, *) AND a runtime check for UIDesignRequiresCompatibility (compatibility mode disables Liquid Glass and uses the legacy view hierarchy) - Set translatesAutoresizingMaskIntoConstraints = NO - Add width/height constraints at UILayoutPriorityDefaultHigh - Update constraints in didMountComponentsWithRootTag: after sizeToFit Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent e4e5049 commit fd43bcc

1 file changed

Lines changed: 41 additions & 2 deletions

File tree

ios/RNNReactButtonView.mm

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#import "RNNReactButtonView.h"
2+
#import <React/RCTSurface.h>
23

3-
@implementation RNNReactButtonView
4+
@implementation RNNReactButtonView {
5+
NSLayoutConstraint *_widthConstraint;
6+
NSLayoutConstraint *_heightConstraint;
7+
}
48

59
- (instancetype)initWithHost:(RCTHost *)host
610
moduleName:(NSString *)moduleName
@@ -10,15 +14,50 @@ - (instancetype)initWithHost:(RCTHost *)host
1014
reactViewReadyBlock:(RNNReactViewReadyCompletionBlock)reactViewReadyBlock {
1115
self = [super initWithHost:host moduleName:moduleName initialProperties:initialProperties eventEmitter:eventEmitter sizeMeasureMode:convertToSurfaceSizeMeasureMode(RCTRootViewSizeFlexibilityWidthAndHeight) reactViewReadyBlock:reactViewReadyBlock];
1216
[host.surfacePresenter addObserver:self];
13-
self.backgroundColor = UIColor.clearColor;
17+
self.backgroundColor = [UIColor clearColor];
18+
19+
if (@available(iOS 26.0, *)) {
20+
if (![self designRequiresCompatibility]) {
21+
self.translatesAutoresizingMaskIntoConstraints = NO;
22+
_widthConstraint = [self.widthAnchor constraintEqualToConstant:0];
23+
_heightConstraint = [self.heightAnchor constraintEqualToConstant:0];
24+
_widthConstraint.priority = UILayoutPriorityDefaultHigh;
25+
_heightConstraint.priority = UILayoutPriorityDefaultHigh;
26+
_widthConstraint.active = YES;
27+
_heightConstraint.active = YES;
28+
}
29+
}
1430

1531
return self;
1632
}
1733

34+
- (BOOL)designRequiresCompatibility {
35+
static BOOL checked = NO;
36+
static BOOL result = NO;
37+
if (!checked) {
38+
checked = YES;
39+
result = [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIDesignRequiresCompatibility"] boolValue];
40+
}
41+
return result;
42+
}
43+
1844
- (void)didMountComponentsWithRootTag:(NSInteger)rootTag {
1945
if (self.surface.rootTag == rootTag) {
2046
[super didMountComponentsWithRootTag:rootTag];
2147
[self sizeToFit];
48+
if (@available(iOS 26.0, *)) {
49+
if (![self designRequiresCompatibility]) {
50+
[self updateConstraintsToFitSize];
51+
}
52+
}
53+
}
54+
}
55+
56+
- (void)updateConstraintsToFitSize {
57+
CGSize size = self.frame.size;
58+
if (size.width > 0 && size.height > 0) {
59+
_widthConstraint.constant = size.width;
60+
_heightConstraint.constant = size.height;
2261
}
2362
}
2463

0 commit comments

Comments
 (0)