localkostya
localkostya

Reputation: 105

Disable page transition at VC pushed by Navigation controller

I have root page view controller with three navigation controllers, each of them initially navigates to view controller with main table. After user clicks on the table there is a segue with push going to another VC (with detail table).

Transition style is scroll.

it's work fine. But, I have following effect: page scrolling works everywhere. I need to scroll between pages only when user in table vc. Left swipe in detail table vc going to previous navigation controller, not back to the main table vc.

What I need to do to correct described behavior? X-Code 5, iOS 7

Upd: I can prevent page transition by returning a nil at datasource before/after methods, but the scrolling is still showing on the screen.

When I tried to disable scroll by setting datasource to nil in 2 ways: 1) in pageViewController:didFinishAnimating) a have an exception: Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: [views count] == 3' 2) in main table vc in willAppear/willDisapper and have an exception: Terminating app due to uncaught exception 'NSGenericException', reason: '* Collection <__NSArrayM: 0x8a445d0> was mutated while being enumerated.'

Upd 2: here the link to my project: http://yadi.sk/d/MWmdA3XLCdn4U . Press a blue button with "download" picture to get the file, or use the language switcher at the bottom of page.

Upd 3: Thanks to David. His solution is working. In addition: I just lay Pan GR at DetailTable VC in my storyboard and link it to a view, without any lines of code.

Upvotes: 0

Views: 713

Answers (1)

David Hoerl
David Hoerl

Reputation: 41682

Two ideas come to mind:

  • subclass UIPageViewController, and in your subclass provide a method to change the array of view controllers from the "real" array to just the current visible one. The user will not see any affect of this, but it will prevent the page controller from doing anything.. Obviously when you get back to the root view, you tell the page view controller to undo the change (swap back to the real array).

  • implement the dataSource protocol, and set a flag so that when you want to prevent paging, the dataSource returns nil for the next/previous view controller.

Note: I have not done this with a pageController, but I have done similar things with navigation controllers.

EDIT1: I played with your project, and yes, its not going to be easy to prevent the scrolling, but it is possible. The key issue is that the page controller has a scrollview subview that is hosting the pages. It has a pan gesture recognizer in it to recognize the dragging behavior and respond to it. Unfortunately, for the "scrolling" variation of the page controller, the gesture recognizers are not exposed. There is an interesting thread on this whole subject here on SO.

So you have a few options:

  • look for the scroll view in the subviews, find the gesture recognizer, and disable it.

  • disable the same scrollView

  • do some fancy tricks after you push the first view controller. But that I mean, once the animation is over, pull that view out of the subviews, remove the paging controller from the window, and install the pulled out view directly as the root view controller. This can be made to work, but since offsets change. you may need to actually create a transparent view the same size as the window and insert the pulled view there first.

  • add your own pan gesture recognizer, and just ignore the results. So in viewDidLoad in any view that you don't want paging, add the code below. It seems to work quite well.

Code:

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self.view addGestureRecognizer:pan];

EDIT2: The preferred way to do this is going to be using your own pan gesture recognizer, as shown in the code above. What you can do is when the view appears that you DO NOT want to activate the paging control, add the gesture recognizer in viewDidLoad. When the user navigates back to the main view, then that pan recognizer will not be active, and the page control will work normally. I tried this with your demo project, it works fine.

While the other ways can be made to work, its more complicated as you see. To change the scrollView or its recognizer, you have to go probing around in the page view subviews, which is something Apple frowns on, and is fragile (meaning it can break easy in the future). You would have to provide public methods in your subclass, and figure out how to get a reference to the page control to each subview.

Upvotes: 2

Related Questions