Ethan Schatzline Ethan Schatzline - 1 year ago 108
iOS Question

UIScreenEdgePanGestureRecognizer inside a UIScrollView

I have a horizontal scroll view with 3 views. The first view (far left) is a map view. The functionality I want is that the user can only go to the second view by swiping from the far right edge, because I want other gestures to manipulate the map. But, from the second and third view, they may move left or right by swiping anywhere on the view. I have searched how to do this and have had no luck with my specific situation.

I am not sure where to start so if someone could just point me in the right direction that would be great.

So far I have tried:

disabling scrolling while on the first view and adding in the code:

let edgeRecognizer = UIScreenEdgePanGestureRecognizer(target: firstView, action: "goToSecondView:")
edgeRecognizer.edges = .Right

func goToSecondView(){
scrollView.contentOffset = CGPoint(x: self.scrollView.contentSize.width/3, y: scrollView.contentOffset.y)

Answer Source

Instead of using a UIScreenEdgePanGestureRecognizer, let's just make the map view not see touches close to the right edge of the screen. That way the touches will pass through to the scroll view's UIPanGestureRecognizer.

Here's my setup:

storyboard layout

(Note: the view frames in the picture do not match the constraints.)

I have a scroll view containing three “page” views. Page 1 (“MapHolder”) contains the map view as a subview. Page 2 (“Pink”) and page 3 (“Green”) just have label subviews, and have a background color to make them easy to see.

The view sizes are constrained as follows:

  • Pages 2 and 3 are constrained to have the same width and height as the root view (which is the superview of the scroll view). This means that each of them will fill the screen.
  • Page 1 (“MapHolder”) is constrained to have the same height as the root view, but is constrained to be the width of the root view minus 44.
  • The map view is constrained to have the same top, bottom, and leading edges as its parent, but to have the same width as the root view.

So notice that the map view is wider than its parent (page 1). The page 1 view has “Clip Subviews” turned off (this is the default), so the part of the map that falls outside of the page 1 view will still be visible, but won't receive touches.

The view positions are constrained as follows:

  • The scroll view has constraints on all four edges to the root view. This means the scroll view will fill the screen.
  • Page 1 has constraints from its top, bottom, and leading edges to the scroll view.
  • Page 2's leading edge is constrained to page 1's trailing edge plus 44.
  • Page 3's leading edge is constrained to be equal to page 2's trailing edge.
  • Page 3's trailing edge is constrained to be equal to the scroll view's trailing edge.
  • The vertical centers of pages 1, 2, and 3 are constrained to be equal.

The constraints from the page views to the scroll view control the scroll view's contentSize.

Finally, I turned on “Paging Enabled” for the scroll view. Result:


I've uploaded my storyboard to this gist. Just put it in a fresh project (replacing the existing Main.storyboard) and link with MapKit to try it out.