Skip to content

Commit 15cac4d

Browse files
committed
fix(ios): improve menu view child component handling
properly clean up menu button and restore disabled views when unmounting track disabled views in a set to avoid duplicate state changes
1 parent f0d8fc7 commit 15cac4d

File tree

1 file changed

+45
-6
lines changed

1 file changed

+45
-6
lines changed

ios/MenuView.mm

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ @implementation MenuView {
1919
UIColor *_textColor;
2020
UIColor *_checkedColor;
2121
UIColor *_uncheckedColor;
22+
BOOL _isChildViewButton;
23+
NSMutableSet<UIView *> *_disabledViews;
2224
}
2325

2426
+ (ComponentDescriptorProvider)componentDescriptorProvider
@@ -31,6 +33,8 @@ - (instancetype)initWithFrame:(CGRect)frame
3133
if (self = [super initWithFrame:frame]) {
3234
static const auto defaultProps = std::make_shared<const MenuViewProps>();
3335
_props = defaultProps;
36+
_disabledViews = [[NSMutableSet alloc] init];
37+
_isChildViewButton = NO;
3438
}
3539

3640
return self;
@@ -42,10 +46,8 @@ - (void)mountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompone
4246
if (index == 0) {
4347
// Clean up old child view if exists
4448
if (_childView && _childView != childComponentView) {
45-
// Remove from our manual tracking without calling removeFromSuperview
46-
// since React will handle the view hierarchy cleanup
47-
_childView = nil;
48-
_menuButton = nil;
49+
[self cleanupMenuButton];
50+
[self restoreUserInteractionForDisabledViews];
4951
}
5052

5153
_childView = (UIView *)childComponentView;
@@ -64,8 +66,9 @@ - (void)unmountChildComponentView:(UIView<RCTComponentViewProtocol> *)childCompo
6466
{
6567
// Clean up our references before React unmounts
6668
if (index == 0 && _childView == childComponentView) {
69+
[self cleanupMenuButton];
70+
[self restoreUserInteractionForDisabledViews];
6771
_childView = nil;
68-
_menuButton = nil;
6972
}
7073

7174
// Let React handle the unmounting
@@ -78,9 +81,11 @@ - (void)setupChildViewAsMenuTrigger:(UIView *)childView
7881
if ([childView isKindOfClass:[UIButton class]]) {
7982
_menuButton = (UIButton *)childView;
8083
_menuButton.showsMenuAsPrimaryAction = YES;
84+
_isChildViewButton = YES;
8185
[self updateMenuItems:_menuItems selectedIdentifier:nil];
8286
} else {
8387
// For non-button children, create an invisible button overlay to show the menu
88+
_isChildViewButton = NO;
8489
[self disableUserInteractionRecursively:childView];
8590

8691
// Create an invisible button that covers the entire view
@@ -105,12 +110,46 @@ - (void)setupChildViewAsMenuTrigger:(UIView *)childView
105110

106111
- (void)disableUserInteractionRecursively:(UIView *)view
107112
{
108-
view.userInteractionEnabled = NO;
113+
if (view.userInteractionEnabled) {
114+
[_disabledViews addObject:view];
115+
view.userInteractionEnabled = NO;
116+
}
109117
for (UIView *subview in view.subviews) {
110118
[self disableUserInteractionRecursively:subview];
111119
}
112120
}
113121

122+
- (void)restoreUserInteractionForDisabledViews
123+
{
124+
for (UIView *view in _disabledViews) {
125+
// Only restore if the view is still in the view hierarchy
126+
if (view.superview != nil) {
127+
view.userInteractionEnabled = YES;
128+
}
129+
}
130+
[_disabledViews removeAllObjects];
131+
}
132+
133+
- (void)cleanupMenuButton
134+
{
135+
if (_menuButton) {
136+
// If it's not a child view button (i.e., it's our overlay button), remove it
137+
if (!_isChildViewButton && _menuButton.superview == self) {
138+
[_menuButton removeFromSuperview];
139+
}
140+
// Clear the menu to prevent any lingering references
141+
_menuButton.menu = nil;
142+
_menuButton = nil;
143+
}
144+
_isChildViewButton = NO;
145+
}
146+
147+
- (void)dealloc
148+
{
149+
[self cleanupMenuButton];
150+
[self restoreUserInteractionForDisabledViews];
151+
}
152+
114153
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
115154
{
116155
const auto &oldViewProps = *std::static_pointer_cast<MenuViewProps const>(_props);

0 commit comments

Comments
 (0)