iosobjective-creact-native

Change ContextMenu iOS apperance (background & highlight color)


I'm working on my React-Native app and I use RN ContextMenu iOS library that was written on top of Native Context Menu component, everything works fine except background & highlight color behavior.

Looks like by default highlight & background color follows iOS theme, so it could be either black or white. Althought this behavior does not fit my app's colors and I wanna change it but I'm competely newbie in objective-c so I can't understand what part should I change.

Just to make it clear I make a little demo that shows ugly white highlight & bg color: https://www.youtube.com/watch?v=AASqQXXtRwE&feature=youtu.be

I belive that I should change something in this file -> https://github.com/mpiannucci/react-native-context-menu-view/blob/master/ios/ContextMenuView.m

Ideally, I would like to make bg color transparent, can you help me guys?


Solution

  • You need to use contextMenuInteraction:previewForHighlightingMenuWithConfiguration: method. It allows to return a custom preview for the ContextMenu, including setting UIPreviewParameters, which includes backgroundColor, which should be set as transparent.


    The main challenge is that it requires a view to display, but in react-native-context-menu-view we only have access to UIContextMenuInteraction at the time of interaction.

    To fix that, we can create an interaction -> view map:

    NSMapTable *interactionToViewMap = [NSMapTable weakToWeakObjectsMapTable];
    

    Then, inside ContextMenuView.m in insertReactSubview: we remember the interaction-to-view association:

    - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex
    {
      [super insertReactSubview:subview atIndex:atIndex];
      if (@available(iOS 13.0, *)) {
        UIContextMenuInteraction* contextInteraction = [[UIContextMenuInteraction alloc] initWithDelegate:self];
        
        // Map interaction to its view, so that we can retrieve view by interaction later
        [interactionToViewMap setObject:subview forKey:contextInteraction]; // <-- new line
    
        [subview addInteraction:contextInteraction];
      }
    }
    

    And then add a method that will use the map to display a preview with transparent background:

    - (nullable UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction previewForHighlightingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration  API_AVAILABLE(ios(13.0)){
      // Set background to transparent to avoid unnecessary highlighting.
      UIPreviewParameters *params = [UIPreviewParameters alloc];
      params.backgroundColor = [UIColor clearColor];
    
      return [[UITargetedPreview alloc] initWithView:[interactionToViewMap objectForKey:interaction] parameters:params];
    }