question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Customize menu action item

See original GitHub issue

Thank you for creating this amazing package 🚀

I’m currently trying to add custom buttons to the context-menu, because not every emoji reaction should be a separate action menu item. That’s why I’ve made a custom preview render, which renders a small bar with pressables.

However when I try to click it the onPress handles don’t get called. I’ve tried to use onPressMenuPreview instead, however the page x & y position of the pressed item don’t get passed to the event handler, only the generic RNIContextMenuView tag is passed.

Is there any way to either customize an action menu item or make the buttons in the preview pressable?

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
dominicstopcommented, Jan 6, 2022

@nandorojo @Flam3rboy hey sorry for the late response haha here are results of my testing ✨

Debug Layout: Screen Shot 2022-01-06 at 6 30 20 PM

(lldb) po self.previewController?.next
▿ Optional<UIResponder>
  - some : <UIViewController: 0x7f7a6f90e100>

(lldb) po self.previewController?.next?.next
▿ Optional<UIResponder>
  - some : <UITransitionView: 0x7f7a73016ab0; frame = (0 0; 375 667); alpha = 0; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x600002f3dea0>>
  • UITransitionView is internal, not published in the SDK

(lldb) po self.previewController?.next?.next?.next
▿ Optional<UIResponder>
  - some : <UIWindow: 0x7f7a6f90d1e0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x60000265f2d0>; layer = <UIWindowLayer: 0x6000026539c0>>
  • Climb responder chain…
  • UIViewController (Preview Content) -> UITransitionView (Internal) -> UIWindow (Main Window)

(lldb) po self.previewController?.presentationController
▿ Optional<UIPresentationController>
  - some : <_UIContextMenuPresentationController: 0x7f7a72365200>

(lldb) po self.previewController?.presentingViewController
▿ Optional<UIViewController>
  - some : <UIViewController: 0x7f7a6f90e100>
  
(lldb) po self.previewController?.presentationController
▿ Optional<UIPresentationController>
  - some : <_UIContextMenuPresentationController: 0x7f7a72365200>

(lldb) po self.previewController?.presentingViewController
▿ Optional<UIViewController>
  - some : <UIViewController: 0x7f7a6f90e100>
  • This is how you get the parent view controller of the preview

(lldb) po self.previewController?.presentingViewController?.view
▿ Optional<UIView>
  - some : <RCTRootView: 0x7f7a6ef3ee90; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x6000028043a0>>

(lldb) po self.window?.rootViewController?.view
▿ Optional<UIView>
  - some : <RCTRootView: 0x7f7a6ef3ee90; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x6000028043a0>>

(lldb) po self.previewController?.presentingViewController?.view === self.window?.rootViewController?.view
true
  • the preview is being presented using the current window’s root view controller
  • Thus, the container view that’s holding the preview content should be one of it’s subviews…

(lldb) po (self.previewController?.next?.next as? UIView)?.gestureRecognizers
nil

(lldb) po (self.previewController?.next?.next as? UIView)
▿ Optional<UIView>
  - some : <UITransitionView: 0x7f7a73016ab0; frame = (0 0; 375 667); alpha = 0; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x600002f3dea0>>
  • userInteractionEnabled is disabled, enabling it does nothing…
  • TLDR: What needs to be done is to become responsible for handling the gestures for the preview controller, but it is not exposed…
  • The moment I try to use the private API’s, app store connect might reject it (I can do some swizzling, or drop down to Obj-C to use them)
  • So lets try a different approach — I mentioned earlier that the container view that’s holding the preview content should be one of it’s subviews…

(lldb) po self.window?.subviews
▿ Optional<Array<UIView>>
  ▿ some : 4 elements
    - 0 : <_UITouchFallbackView: 0x7fe89f62f8b0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x600002c69fe0>>
    - 1 : <UITransitionView: 0x7fe89d00a320; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x600002855620>>
    - 2 : <UITransitionView: 0x7fe89d0837b0; frame = (0 0; 375 667); alpha = 0; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x600002c50520>>
    - 3 : <_UIContextMenuContainerView: 0x7fe89d07e6d0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x60000248d7d0>; layer = <CALayer: 0x600002c505a0>>
  • _UIContextMenuContainerView is the view that’s holding our preview content (along with the context menu buttons)

(lldb) po self.window?.subviews.first { ($0.gestureRecognizers?.count ?? 0) > 0 }
▿ Optional<UIView>
  - some : <_UIContextMenuContainerView: 0x7fe89d07e6d0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x60000248d7d0>; layer = <CALayer: 0x600002c505a0>>
  
  • _UIContextMenuContainerView is internal, so we can’t cast to it… so we search for the view that has a bunch of gesture recoginizer
    • We could filter it via it’s internal class name using reflection (e.g. NSStringFromClass), but referencing internal classes will get out app flag by app review haha

(lldb) po self.window?.subviews.first { ($0.gestureRecognizers?.count ?? 0) > 0 }?.gestureRecognizers
▿ Optional<Array<UIGestureRecognizer>>
  ▿ some : 3 elements
    - 0 : <UIPanGestureRecognizer: 0x7fc6021ae860 (com.apple.UIKit.PreviewPlatterPan); state = Possible; enabled = NO; cancelsTouchesInView = NO; view = <_UIContextMenuContainerView 0x7fc60225ec90>; target= <(action=_handlePanGesture:, target=<_UIContextMenuPanController 0x6000034407e0>)>>
    - 1 : <UITapGestureRecognizer: 0x7fc6021aea00 (com.apple.UIKit.ContextMenuDismissalTap); state = Possible; enabled = NO; view = <_UIContextMenuContainerView 0x7fc60225ec90>; target= <(action=_handleDismissalTapGesture:, target=<_UIContextMenuPresentationController 0x7fc6022068b0>)>>
    - 2 : <_UIContextMenuActionScrubbingHandoffGestureRecognizer: 0x7fc6021aeb20 (com.apple.UIKit.ContextMenuActionPanHandoff); state = Possible; enabled = NO; cancelsTouchesInView = NO; view = <_UIContextMenuContainerView 0x7fc60225ec90>; target= <(action=_handleActionHandoffGesture:, target=<_UIContextMenuPresentationController 0x7fc6022068b0>)>>
    
po self.window?.subviews.first { ($0.gestureRecognizers?.count ?? 0) > 0 }?.gestureRecognizers?.forEach { $0.isEnabled = false }
  • Even after disabling the gesture recognizers, the preview content still dont receive any touch events…


Summary: interactive context menu’s are still not possible in iOS 15 😔 (if you have any more ideas I can try, please let me know haha, but for now, I’ll be closing the issue — if i find another way, I’ll update this)

Note: I could not find any resources on the internet for making context menu previews interactive, so the following are just based on my tinkering haha

1reaction
nandorojocommented, Jun 18, 2022

Yeah, see renderAuxiliaryPreview

Read more comments on GitHub >

github_iconTop Results From Across the Web

Custom Action Menu Items - SG Developer
API developers can customize context menu items on a per-entity basis, through Action Menu Items (AMIs). For example, from a Versions page, you...
Read more >
Menus - Android Developers
The options menu is the primary collection of menu items for an activity. It's where you should place actions that have a global...
Read more >
Defining Action Menu Items - Oracle Help Center
From the Home page, click Navigator Navigator icon , and then under Create and Manage, click Action Menus. · Select a menu and...
Read more >
Set up a custom action menu for list and list records
Open the [ Freedom UI page ] schema that contains the list. · Go to the viewConfigDiff schema section and find the configuration...
Read more >
Menus and actions - Components - Human Interface Guidelines
A single menu item that displays a label that can change depending on the current state, such as Show Ruler and Hide Ruler....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found