Search code examples
iosswiftuikituigesturerecognizeruievent

Make sibling view ignore any touch input, the other sibling view should receive it


I develop a Calendar library similar to the default iOS Calendar app, Day View (agenda).

The calendar displays events which are subclasses of the UIView. The events can be tapped, long-pressed or could handle other gesture-based user interaction.

Sometimes a CurrentTimeIndicator which is also a composed UIView subclass could overlap the Event.

Both, the Event and the CurrentTimeIndicator share a common superview, TimelineView.

Together, they look like this:

timeline view

When there is no CurrentTimeIndicator on top of the Event, everything works fine and I could trigger user interaction events by tapping the view. However, when the CurrentTimeIndicator overlaps the Event, the touch event's received by the indicator are ignored and not passed to the underlying Event view.

The goal is to exclude CurrentTimeIndicator from the responder chain completely, but let the Event handle any touch events, even if obscured by the CurrentTimeIndicator.

View hierarchy: view hierarchy

Both, the indicator and the event are sibling views. When tapping on the event in the highlighted touch are, the touches are not delivered.

So far, I've tried experimenting with userInteractionEnabled = true / false, overriding hitTest:withEvent: method.

What are the other approaches to fix the issue?

Code references:

Event View - creating gesture recognizers Timeline - layout current time indicator Current Time Indicator - code

Conceptually, I'm looking to something similar to the zPosition property of the CALayer, but for the touch input.


Solution

  • Override the pointInside method inside your CurrentTimeIndicator view:

      override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
          print("Passing all touches to the next view (if any), in the view stack.")
          return false
      }
    

    as answered here: iOS - forward all touches through a view