Detect that a PDFView did scroll - ios

Does PDFKit on iOS expose a PDFView's underlying UIScrollView or is there any other way to directly detect that the user has scrolled a PDFView?
My use case is to hide a nav bar when the document is scrolled so as a workaround I've added my own pan gesture recogniser to the PDFView's parent and I do the hiding in gestureRecognizerShouldBegin and always return false but I expect there's something more like UIScrollViewDelegate that I'm missing in the docs.

Try this,
NotificationCenter.default.addObserver(self, selector: #selector(handlePageChange(notification:)), name: Notification.Name.PDFViewPageChanged, object: nil)
#objc private func handlePageChange(notification: Notification)
{
print("Page changed")
}

Does PDFKit on iOS expose a PDFView's underlying UIScrollView
No, but hopefully Apple will add this in the future. I remember that UIWebView didn't have it originally and it was added later.
or is there any other way to directly detect that the user has scrolled a PDFView
No, it looks like none of the notifications provided by PDFViewDelegate address this.
I'm migrating from UIWebView to PDFView and am using scrollViewDidScroll for a bunch of stuff, so I didn't want to rely on just adding a pan gesture recognizer. Building from #Matthijs's answer, I'm finding the UIScrollView inside the PDFView, making my class its delegate, then passing any events back to the scroll view (which was its own delegate before my class became the delegate) so it can respond to them, too. With UIWebView, this last step was not necessary, but with PDFView, zooming and possibly other functions won't work without it.
I'm overriding all the documented delegate methods to reduce the chance that this will break if Apple changes the internal function of PDFView. However, I had to check respondsToSelector in each method, because the original scroll view delegate doesn't currently implement all of them.
- (void)viewDidLoad {
// create the PDFView and find its inner scrollView
self.pdfView = [[PDFView alloc] init];
for (UIView *subview in self.pdfView.subviews) {
if ([subview isKindOfClass:[UIScrollView class]]) {
self.scrollView = (UIScrollView *)subview;
} else {
for (UIView *subsubview in subview.subviews) {
if ([subsubview isKindOfClass:[UIScrollView class]]) {
self.scrollView = (UIScrollView *)subsubview;
}
}
}
}
}
- (void)loadPDFDocument:(NSString *)URL {
// load a document, then become the delegate for the scrollView (we have to do that after loading the document)
PDFDocument *document = [[PDFDocument alloc] initWithURL:URL];
self.pdfView.document = document;
self.scrollView.delegate = self;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// *** respond to scroll events here ***
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidScroll:)]) {
[scrollViewDelegate scrollViewDidScroll:scrollView];
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewWillBeginDragging:)]) {
[scrollViewDelegate scrollViewWillBeginDragging:scrollView];
}
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
[scrollViewDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidEndDragging:willDecelerate:)]) {
[scrollViewDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
}
}
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewShouldScrollToTop:)]) {
return [scrollViewDelegate scrollViewShouldScrollToTop:scrollView];
}
return TRUE;
}
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidScrollToTop:)]) {
[scrollViewDelegate scrollViewDidScrollToTop:scrollView];
}
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewWillBeginDecelerating:)]) {
[scrollViewDelegate scrollViewWillBeginDecelerating:scrollView];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidEndDecelerating:)]) {
[scrollViewDelegate scrollViewDidEndDecelerating:scrollView];
}
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(viewForZoomingInScrollView:)]) {
return [scrollViewDelegate viewForZoomingInScrollView:scrollView];
}
return nil;
}
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewWillBeginZooming:withView:)]) {
[scrollViewDelegate scrollViewWillBeginZooming:scrollView withView:view];
}
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidEndZooming:withView:atScale:)]) {
[scrollViewDelegate scrollViewDidEndZooming:scrollView withView:view atScale:scale];
}
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidZoom:)]) {
[scrollViewDelegate scrollViewDidZoom:scrollView];
}
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidEndScrollingAnimation:)]) {
[scrollViewDelegate scrollViewDidEndScrollingAnimation:scrollView];
}
}
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:#selector(scrollViewDidChangeAdjustedContentInset:)]) {
[scrollViewDelegate scrollViewDidChangeAdjustedContentInset:scrollView];
}
}

I did this to detect zooming and panning on a pdfView to copy those gestures to a second pdfView, and it's working perfectly fine here.
Got some help to detect vertical and horizontal panning by the PanDirectionGestureRecognizer I found here: stackoverflow.com/a/55635482/558112
class Document: UIViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Subscribe to notifications.
NotificationCenter.default.addObserver(self, selector: #selector(onPageZoomAndPan), name: .PDFViewScaleChanged, object: pdfView
// get the scrollView in pdfView and attach gesture recognizers
outerLoop: for subView in pdfView.subviews {
for view in subView.subviews {
if let scrollView = view as? UIScrollView {
let xScrollViewPanGesture = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(onPageZoomAndPan))
xScrollViewPanGesture.delegate = self
scrollView.addGestureRecognizer(xScrollViewPanGesture)
let yScrollViewPanGesture = PanDirectionGestureRecognizer(direction: .vertical, target: self, action: #selector(onPageZoomAndPan))
yScrollViewPanGesture.delegate = self
scrollView.addGestureRecognizer(yScrollViewPanGesture)
break outerLoop
}
}
}
}
// MARK: - UIScrollViewDelegate
#objc private func onPageZoomAndPan() {
let rect = pdfView.convert(pdfView.bounds, to: pdfView.currentPage!)
pdfViewSecondScreen.scaleFactor = pdfView.scaleFactor
pdfViewSecondScreen.go(to: rect, on: pdfView.currentPage!)
}
}
enum PanDirection {
case vertical
case horizontal
}
// UIKit.UIGestureRecognizerSubclass
import UIKit.UIGestureRecognizerSubclass
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction : PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if state == .began {
let vel = velocity(in: self.view!)
switch direction {
case .horizontal where abs(vel.y) > abs(vel.x):
state = .cancelled
case .vertical where abs(vel.x) > abs(vel.y):
state = .cancelled
default:
break
}
}
}
}

Decided on a solution other's haven't done yet. Went with key value observing on the contentOffset property of the underlying UIScrollView.
You can use this extension to run a callback every time the scroll offset changes.
var observation = pdfView.onScrollOffsetChanged { scroll in
print("PDFView scrolled to \(scroll.contentOffset).")
}
The extension
extension PDFView {
func onScrollOffsetChange(handler: #escaping (UIScrollView) -> Void) -> NSKeyValueObservation? {
detectScrollView()?.observe(\.contentOffset) { scroll, _ in
handler(scroll)
}
}
private func detectScrollView() -> UIScrollView? {
for view in subviews {
if let scroll = view as? UIScrollView {
return scroll
} else {
for subview in view.subviews {
if let scroll = subview as? UIScrollView {
return scroll
}
}
}
}
print("Unable to find a scrollView subview on a PDFView.")
return nil
}
}

try this!
(pdfView.subviews[0] as? UIScrollView)?.delegate = self
and observe the scrollview delegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
/// ...
} else {
/// ...
}
}

Related

Hide navigation bar when scrolling web view without navigation controller in iOS

I want the same behaviour as this
How do you hide navigation bar when scrolling in web view if the main view has a navigation bar without a navigationController? Navigation bars don't have the alternative via storyboard to check 'hide bars on swipe'.
This will not work either
self.navigationController.hidesBarsOnSwipe = true
This is what my SB looks like:
Regards
you might try the following solution:
Swift
import UIKit
class ViewController: UIViewController, UIScrollViewDelegate {
#IBOutlet var webView:UIWebView!
#IBOutlet var navigationBar:UINavigationBar!
#IBOutlet var navigationBarTop:NSLayoutConstraint!
var lastContentOffset:CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
self.webView.scrollView.delegate = self
self.webView.loadRequest(URLRequest(url: URL(string: "https://www.apple.com")!))
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
let threshold:CGFloat = 20.0
let delta = abs(self.lastContentOffset - scrollView.contentOffset.y)
if delta > threshold || scrollView.contentOffset.y <= 0 {
if self.lastContentOffset > scrollView.contentOffset.y && self.navigationBarTop.constant < 0 && (self.lastContentOffset < (scrollView.contentSize.height - scrollView.frame.height)) {
self.showNavBar(true)
} else if (self.lastContentOffset < scrollView.contentOffset.y && self.navigationBarTop.constant == 0 && (self.lastContentOffset > 0)) {
self.showNavBar(false)
}
}
self.lastContentOffset = scrollView.contentOffset.y;
}
func showNavBar(_ isVisible:Bool) {
UIView.animate(withDuration: 0.25, animations: {
self.navigationBarTop.constant = isVisible ? 0 : -(self.navigationBar.frame.height + UIApplication.shared.statusBarFrame.height)
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
})
}
}
full source code here: https://github.com/mugx/AnimatedNavigationBar
Objective-C
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UIScrollViewDelegate>
#property IBOutlet UIWebView *webView;
#property IBOutlet UINavigationBar *navigationBar;
#property IBOutlet NSLayoutConstraint *navigationBarTop;
#property (nonatomic,assign) CGFloat lastContentOffset;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.webView.scrollView.delegate = self;
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"https://www.apple.com"]]];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat threshold = 20.0;
CGFloat delta = fabs(self.lastContentOffset - scrollView.contentOffset.y);
if (delta > threshold || scrollView.contentOffset.y <= 0) {
if (self.lastContentOffset > scrollView.contentOffset.y && self.navigationBarTop.constant < 0 && (self.lastContentOffset < (scrollView.contentSize.height - scrollView.frame.size.height))) {
[self showNavBar:true];
} else if (self.lastContentOffset < scrollView.contentOffset.y && self.navigationBarTop.constant == 0 && (self.lastContentOffset > 0)) {
[self showNavBar:false];
}
}
self.lastContentOffset = scrollView.contentOffset.y;
}
- (void)showNavBar:(Boolean)isVisible {
[UIView animateWithDuration:0.25 animations:^{
self.navigationBarTop.constant = isVisible ? 0 : -(self.navigationBar.frame.size.height + UIApplication.sharedApplication.statusBarFrame.size.height);
[self.view setNeedsLayout];
[self.view layoutIfNeeded];
}];
}
#end
This is the first solution I thought, of course is not drag and drop, you have to link the respective IBOutlet. Anyway the mechanism I think is clear, leverage on scrollView delegate embedded in the webview, then calculate the delta offset in order to show/hide (with a smooth animation) your custom navigation bar. If something is not clear, I'll modify the answer.
webView.scrollView.delegate = self
extension ViewController:UIScrollViewDelegate{
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
navigationController?.hidesBarsOnSwipe = velocity.y > 0
}
}

How to disable delaysContentTouches in UITableViewController? [duplicate]

I've looked at a ton of posts on similar things, but none of them quite match or fix this issue. Since iOS 7, whenever I add a UIButton to a UITableViewCell or even to the footerview it works "fine", meaning it receives the target action, but it doesn't show the little highlight that normally happens as you tap a UIButton. It makes the UI look funky not showing the button react to touch.
I'm pretty sure this counts as a bug in iOS7, but has anyone found a solution or could help me find one :)
Edit:
I forgot to mention that it will highlight if I long hold on the button, but not a quick tap like it does if just added to a standard view.
Code:
Creating the button:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.titleLabel.font = [UIFont systemFontOfSize:14];
button.titleLabel.textColor = [UIColor blueColor];
[button setTitle:#"Testing" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents: UIControlEventTouchDown];
button.frame = CGRectMake(0, 0, self.view.frame.size.width/2, 40);
Things I've Tested:
//Removing gesture recognizers on UITableView in case they were getting in the way.
for (UIGestureRecognizer *recognizer in self.tableView.gestureRecognizers) {
recognizer.enabled = NO;
}
//Removing gestures from the Cell
for (UIGestureRecognizer *recognizer in self.contentView.gestureRecognizers) {
recognizer.enabled = NO;
}
//This shows the little light touch, but this isn't the desired look
button.showsTouchWhenHighlighted = YES;
In that tableview you just add this property.
tableview.delaysContentTouches = NO;
And add in cellForRowAtIndexPath after you initiate the cell you just add below code. The structure of the cell is apparently different in iOS 6 and iOS 7.
iOS 7 we have one control UITableViewCellScrollView In between UITableViewCell and content View.
for (id obj in cell.subviews)
{
if ([NSStringFromClass([obj class]) isEqualToString:#"UITableViewCellScrollView"])
{
UIScrollView *scroll = (UIScrollView *) obj;
scroll.delaysContentTouches = NO;
break;
}
}
Since iOS 8 we need to apply the same technique to UITableView subviews (table contains a hidden UITableViewWrapperView scroll view). There is no need iterate UITableViewCell subviews anymore.
for (UIView *currentView in tableView.subviews) {
if ([currentView isKindOfClass:[UIScrollView class]]) {
((UIScrollView *)currentView).delaysContentTouches = NO;
break;
}
}
This answer should be linked with this question.
I tried to add this to the accepted answer but it never went through. This is a much safer way of turning off the cells delaysContentTouches property as it does not look for a specific class, but rather anything that responds to the selector.
In Cell:
for (id obj in self.subviews) {
if ([obj respondsToSelector:#selector(setDelaysContentTouches:)]) {
[obj setDelaysContentTouches:NO];
}
}
In TableView:
self.tableView.delaysContentTouches = NO;
For a solution that works in both iOS7 and iOS8, create a custom UITableView subclass and custom UITableViewCell subclass.
Use this sample UITableView's initWithFrame:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// iterate over all the UITableView's subviews
for (id view in self.subviews)
{
// looking for a UITableViewWrapperView
if ([NSStringFromClass([view class]) isEqualToString:#"UITableViewWrapperView"])
{
// this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
Use this sample UITableViewCell's initWithStyle:reuseIdentifier:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// iterate over all the UITableViewCell's subviews
for (id view in self.subviews)
{
// looking for a UITableViewCellScrollView
if ([NSStringFromClass([view class]) isEqualToString:#"UITableViewCellScrollView"])
{
// this test is here for safety only, also there is no UITableViewCellScrollView in iOS8
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
What I did to solve the problem was a category of UIButton using the following code :
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
[NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = YES; }];
}
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesCancelled:touches withEvent:event];
[self performSelector:#selector(setDefault) withObject:nil afterDelay:0.1];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesEnded:touches withEvent:event];
[self performSelector:#selector(setDefault) withObject:nil afterDelay:0.1];
}
- (void)setDefault
{
[NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = NO; }];
}
the button reacts correctly when I press on it in a UITableViewCell, and my UITableView behaves normally as the delaysContentTouches isn't forced.
Here's Roman B's answer in Swift 2:
for view in tableView.subviews {
if view is UIScrollView {
(view as? UIScrollView)!.delaysContentTouches = false
break
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
for (id view in self.tableView.subviews)
{
// looking for a UITableViewWrapperView
if ([NSStringFromClass([view class]) isEqualToString:#"UITableViewWrapperView"])
{
// this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
I was having similar issues with a text-only UIButton in a UITableViewCell not highlighting upon touch. What fixed it for me was changing the buttonType from Custom back to System.
Setting delaysContentTouches to NO did the trick for the image-only UIButton in the same UITableViewCell.
self.tableView.delaysContentTouches = NO;
This is a Swift version of Raphaƫl Pinto's answer above. Don't forget to upvote him too :)
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
super.touchesBegan(touches, withEvent: event)
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = true }
}
override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) {
super.touchesCancelled(touches, withEvent: event)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
self.setDefault()
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
super.touchesEnded(touches, withEvent: event)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue()) {
self.setDefault()
}
}
func setDefault() {
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = false }
}
Solution in Swift, iOS8 only (needs the extra work on each of the cells for iOS7):
//
// NoDelayTableView.swift
// DivineBiblePhone
//
// Created by Chris Hulbert on 30/03/2015.
// Copyright (c) 2015 Chris Hulbert. All rights reserved.
//
// This solves the delayed-tap issue on buttons on cells.
import UIKit
class NoDelayTableView: UITableView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
delaysContentTouches = false
// This solves the iOS8 delayed-tap issue.
// http://stackoverflow.com/questions/19256996/uibutton-not-showing-highlight-on-tap-in-ios7
for view in subviews {
if let scroll = view as? UIScrollView {
scroll.delaysContentTouches = false
}
}
}
override func touchesShouldCancelInContentView(view: UIView!) -> Bool {
// So that if you tap and drag, it cancels the tap.
return true
}
}
To use, all you have to do is change the class to NoDelayTableView in your storyboard.
I can confirm that in iOS8, buttons placed inside a contentView in a cell now highlight instantly.
Slightly modified version of Chris Harrison's answer. Swift 2.3:
class HighlightButton: UIButton {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesBegan(touches, withEvent: event)
NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = true }
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
super.touchesCancelled(touches, withEvent: event)
setDefault()
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
setDefault()
}
private func setDefault() {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = false }
}
}
}
The accepted answer did not work at some "taps" for me .
Finally I add the bellow code in a uibutton category(/subclass),and it works a hundred percent.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.backgroundColor = [UIColor greenColor];
[UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
self.backgroundColor = [UIColor clearColor];
} completion:^(BOOL finished)
{
}];
[super touchesBegan:touches withEvent:event];
}
I wrote a category extension on UITableViewCell to make this issue simple to address. It does basically the same thing as the accepted answer except I walk up the view hierarchy (as opposed to down) from the UITableViewCell contentView.
I considered a fully "automagic" solution that would make all cells added to a UITableView set their delaysContentTouches state to match the owning UITableView's delaysContentTouches state. To make this work I'd have to either swizzle UITableView, or require the developer to use a UITableView subclass. Not wanting to require either I settled on this solution which I feel is simpler and more flexible.
Category extension and sample harness here:
https://github.com/TomSwift/UITableViewCell-TS_delaysContentTouches
It's dead-simple to use:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// using static cells from storyboard...
UITableViewCell* cell = [super tableView: tableView cellForRowAtIndexPath: indexPath];
cell.ts_delaysContentTouches = NO;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
Here's the code for the category:
#interface UITableViewCell (TS_delaysContentTouches)
#property (nonatomic, assign) BOOL ts_delaysContentTouches;
#end
#implementation UITableViewCell (TS_delaysContentTouches)
- (UIScrollView*) ts_scrollView
{
id sv = self.contentView.superview;
while ( ![sv isKindOfClass: [UIScrollView class]] && sv != self )
{
sv = [sv superview];
}
return sv == self ? nil : sv;
}
- (void) setTs_delaysContentTouches:(BOOL)delaysContentTouches
{
[self willChangeValueForKey: #"ts_delaysContentTouches"];
[[self ts_scrollView] setDelaysContentTouches: delaysContentTouches];
[self didChangeValueForKey: #"ts_delaysContentTouches"];
}
- (BOOL) ts_delaysContentTouches
{
return [[self ts_scrollView] delaysContentTouches];
}
#end
Since objc is dynamic, and scrollView is the only class that responds to delaysContentTouches, this should work for both ios 7 and 8 (put it somewhere early in your tableViewController, like awakeFromNib):
for (id view in self.tableView.subviews)
{
if ([view respondsToSelector:#selector(delaysContentTouches)]) {
UIScrollView *scrollView = (UIScrollView *)view;
scrollView.delaysContentTouches = NO;
break;
}
}
You may also have to turn off "delaysContentTouches" in your storyboard or nib by selecting the table inside your viewController. BTW, this might not work on ios 7 if you're using a tableView inside a viewController, at least I couldn't get it to work.
That solution for me doesn't work, I fixed subclassing TableView and implementing these two methods
- (instancetype)initWithCoder:(NSCoder *)coder{
self = [super initWithCoder:coder];
if (self) {
for (id obj in self.subviews) {
if ([obj respondsToSelector:#selector(setDelaysContentTouches:)]){
[obj performSelector:#selector(setDelaysContentTouches:) withObject:NO];
}
}
}
return self;
}
- (BOOL)delaysContentTouches{
return NO;
}
Solution in Swift for iOS 7 and 8:
First I wrote a utility function:
class func classNameAsString(obj: AnyObject) -> String {
return _stdlib_getDemangledTypeName(obj).componentsSeparatedByString(".").last!
}
then I subclass UITableView and implement this:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
for view in self.subviews {
if (Utility.classNameAsString(view) == "UITableViewWrapperView") {
if view.isKindOfClass(UIScrollView) {
var scroll = (view as UIScrollView)
scroll.delaysContentTouches = false
}
break
}
}
}
I also subclass UITableViewCell and implement this:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
for view in self.subviews {
if (Utility.classNameAsString(view) == "UITableViewCellScrollView") {
if view.isKindOfClass(UIScrollView) {
var scroll = (view as UIScrollView)
scroll.delaysContentTouches = false
}
}
}
}
In my case the init(coder:) will run. Please put debug point in your init functions to know which init function will run, then using the code above to make it work.
Hope to help someone.
In Swift 3 this UIView extension can be used on the UITableViewCell. Preferably in the cellForRowAt method.
func removeTouchDelayForSubviews() {
for subview in subviews {
if let scrollView = subview as? UIScrollView {
scrollView.delaysContentTouches = false
} else {
subview.removeTouchDelayForSubviews()
}
}
}

How to disable scrolling while using UIPanGestureRecognizer on a UIView

In my app I have a draggable UIView contained in a UIScrollView so that I can zoom it. This moving UIView has a UIPanGestureRecognizer but if I zoom in first and then I try to move the UIView, that does not happen and instead the scrolling is performed as if the UIPanGestureRecognizer is not detected.
This is my associated method to the UIPanGestureRecognizer:
func handlePan(recognizer: UIPanGestureRecognizer) {
if (self.panRec.state == UIGestureRecognizerState.Began) {
self.scrollViewContainer.scrollEnabled = false
}
else if (self.panRec.state == UIGestureRecognizerState.Ended) {
self.scrollViewContainer.scrollEnabled = true
}
let translation = recognizer.translationInView(self)
if let view = recognizer.view {
self.center = CGPoint(x:view.center.x + translation.x,
y:view.center.y + translation.y)
}
recognizer.setTranslation(CGPointZero, inView: self)
self.updatePinsPosition()
}
As you can see I try to disable scrolling when the the user taps in the draggable UIView and reactivate it at the end but it doesn't work. Where am I making a mistake? What am I missing?
UPDATE
So explain myself better, I have a UIScrollView which contains a UIView and inside this last there are some other UIViews acting as pinch, the azure ones. I decided to use a further UIView as container so that the sub views are zoomed all together by scrolling. So, my zoom code is the following:
class PhotoViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIScrollViewDelegate {
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var containerView: ContainerController!
override func viewDidLoad() {
...
self.scrollView.delegate = self
self.scrollView.showsVerticalScrollIndicator = true
self.scrollView.flashScrollIndicators()
self.scrollView.minimumZoomScale = 1.0
self.scrollView.maximumZoomScale = 10.0
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return self.containerView
}
}
You have to override this method of Scrollview Delegate in your ViewController for both zooming and panning
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale {
scale *= [[[self.scrollView window] screen] scale];
[view setContentScaleFactor:scale]; // View which you want to Zoom & pan.
for (UIView *subview in view.subviews) {
[subview setContentScaleFactor:scale]; // all the Container Views
}
}
Hope it will help you to solve your problem.

UIButton not showing highlight on tap in iOS7 - Swift

From this post they said that it is kind of a bug in ios 7 and 8 - Button in UITableViewCell does not change to highlighted when tapped. Here I post one answer for this in Objective-C:
Create a custom UITableView subclass and custom UITableViewCell subclass.
Use this sample UITableView's initWithFrame:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
// iterate over all the UITableView's subviews
for (id view in self.subviews)
{
// looking for a UITableViewWrapperView
if ([NSStringFromClass([view class]) isEqualToString:#"UITableViewWrapperView"])
{
// this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
Use this sample UITableViewCell's initWithStyle:reuseIdentifier:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// iterate over all the UITableViewCell's subviews
for (id view in self.subviews)
{
// looking for a UITableViewCellScrollView
if ([NSStringFromClass([view class]) isEqualToString:#"UITableViewCellScrollView"])
{
// this test is here for safety only, also there is no UITableViewCellScrollView in iOS8
if([view isKindOfClass:[UIScrollView class]])
{
// turn OFF delaysContentTouches in the hidden subview
UIScrollView *scroll = (UIScrollView *) view;
scroll.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
However I cannot write in Swift. There are some problem:
1) I cannot do
self = super.init(style: style, reuseIdentifier: reuseIdentifier)
Error: Cannot assign to 'self' in a method
2) In Swift, I cannot do
view.class
as in Objective C:
[view class]
I have searched for hours but still cannot get what I want.
Please anyone can answer this in Swift?
In Swift, to call the superclass's designated initialiser, instead of calling self = [super initWithStyle:style reuseIdentifier:reuseIdentifier], you just use super.init(style: style, reuseIdentifier: reuseIdentifier)
Thanks to Schemetrical, this is the working version for me. (iOS 7 + 8)
First I wrote a utility function:
class func classNameAsString(obj: AnyObject) -> String {
return _stdlib_getDemangledTypeName(obj).componentsSeparatedByString(".").last!
}
then I subclass UITableView and implement this:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
for view in self.subviews {
if (Utility.classNameAsString(view) == "UITableViewWrapperView") {
if view.isKindOfClass(UIScrollView) {
var scroll = (view as UIScrollView)
scroll.delaysContentTouches = false
}
break
}
}
}
I also subclass UITableViewCell and implement this:
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
for view in self.subviews {
if (Utility.classNameAsString(view) == "UITableViewCellScrollView") {
if view.isKindOfClass(UIScrollView) {
var scroll = (view as UIScrollView)
scroll.delaysContentTouches = false
}
}
}
}

Navigation pop view when swipe right like Instagram iPhone app.How i achieve this?

I want to pop a view when swipe right on screen or it's work like back button of navigation bar.
I am using:
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
This single line of code for pop navigation view and it's a work for me but when i swipe form middle of screen this will not work like Instagram iPhone app.
Here i give a one screen of Instagram app in that you can see the Example of swipe right pop navigation view:
Apple's automatic implementation of the "swipe right to pop VC" only works for the left ~20 points of the screen. This way, they make sure they don't mess with your app's functionalities. Imagine you have a UIScrollView on screen, and you can't swipe right because it keeps poping VCs out. This wouldn't be nice.
Apple says here :
interactivePopGestureRecognizer
The gesture recognizer responsible for popping the top view controller off the navigation stack. (read-only)
#property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer
The navigation controller installs this gesture recognizer on its view
and uses it to pop the topmost view controller off the navigation
stack. You can use this property to retrieve the gesture recognizer
and tie it to the behavior of other gesture recognizers in your user
interface. When tying your gesture recognizers together, make sure
they recognize their gestures simultaneously to ensure that your
gesture recognizers are given a chance to handle the event.
So you will have to implement your own UIGestureRecognizer, and tie its behavior to the interactivePopGestureRecognizer of your UIViewController.
Edit :
Here is a solution I built. You can implement your own transition conforming to the UIViewControllerAnimatedTransitioning delegate. This solution works, but has not been thoroughly tested.
You will get an interactive sliding transition to pop your ViewControllers. You can slide to right from anywhere in the view.
Known issue : if you start the pan and stop before half the width of the view, the transition is canceled (expected behavior). During this process, the views reset to their original frames. Their is a visual glitch during this animation.
The classes of the example are the following :
UINavigationController > ViewController > SecondViewController
CustomPopTransition.h :
#import <Foundation/Foundation.h>
#interface CustomPopTransition : NSObject <UIViewControllerAnimatedTransitioning>
#end
CustomPopTransition.m :
#import "CustomPopTransition.h"
#import "SecondViewController.h"
#import "ViewController.h"
#implementation CustomPopTransition
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
return 0.3;
}
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
SecondViewController *fromViewController = (SecondViewController*)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
ViewController *toViewController = (ViewController*)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
UIView *containerView = [transitionContext containerView];
[containerView addSubview:toViewController.view];
[containerView bringSubviewToFront:fromViewController.view];
// Setup the initial view states
toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];
[UIView animateWithDuration:0.3 animations:^{
fromViewController.view.frame = CGRectMake(toViewController.view.frame.size.width, fromViewController.view.frame.origin.y, fromViewController.view.frame.size.width, fromViewController.view.frame.size.height);
} completion:^(BOOL finished) {
// Declare that we've finished
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
}];
}
#end
SecondViewController.h :
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UINavigationControllerDelegate>
#end
SecondViewController.m :
#import "SecondViewController.h"
#import "ViewController.h"
#import "CustomPopTransition.h"
#interface SecondViewController ()
#property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactivePopTransition;
#end
#implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.delegate = self;
UIPanGestureRecognizer *popRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePopRecognizer:)];
[self.view addGestureRecognizer:popRecognizer];
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
// Stop being the navigation controller's delegate
if (self.navigationController.delegate == self) {
self.navigationController.delegate = nil;
}
}
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC {
// Check if we're transitioning from this view controller to a DSLSecondViewController
if (fromVC == self && [toVC isKindOfClass:[ViewController class]]) {
return [[CustomPopTransition alloc] init];
}
else {
return nil;
}
}
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
// Check if this is for our custom transition
if ([animationController isKindOfClass:[CustomPopTransition class]]) {
return self.interactivePopTransition;
}
else {
return nil;
}
}
- (void)handlePopRecognizer:(UIPanGestureRecognizer*)recognizer {
// Calculate how far the user has dragged across the view
CGFloat progress = [recognizer translationInView:self.view].x / (self.view.bounds.size.width * 1.0);
progress = MIN(1.0, MAX(0.0, progress));
if (recognizer.state == UIGestureRecognizerStateBegan) {
NSLog(#"began");
// Create a interactive transition and pop the view controller
self.interactivePopTransition = [[UIPercentDrivenInteractiveTransition alloc] init];
[self.navigationController popViewControllerAnimated:YES];
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
NSLog(#"changed");
// Update the interactive transition's progress
[self.interactivePopTransition updateInteractiveTransition:progress];
}
else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
NSLog(#"ended/cancelled");
// Finish or cancel the interactive transition
if (progress > 0.5) {
[self.interactivePopTransition finishInteractiveTransition];
}
else {
[self.interactivePopTransition cancelInteractiveTransition];
}
self.interactivePopTransition = nil;
}
}
#end
Create a pan gesture recogniser and move the interactive pop gesture recogniser's targets across.
Add your recogniser to the pushed view controller's viewDidLoad and voila!
let popGestureRecognizer = self.navigationController!.interactivePopGestureRecognizer!
if let targets = popGestureRecognizer.value(forKey: "targets") as? NSMutableArray {
let gestureRecognizer = UIPanGestureRecognizer()
gestureRecognizer.setValue(targets, forKey: "targets")
self.view.addGestureRecognizer(gestureRecognizer)
}
Here's a Swift version of Spynet's answer, with a few modifications. Firstly, I've defined a linear curve for the UIView animation. Secondly, I've added a semi-transparent black background to the view underneath for a better effect. Thirdly, I've subclassed a UINavigationController. This allows the transition to be applied to any "Pop" transition within the UINavigationController. Here's the code:
CustomPopTransition.swift
import UIKit
class CustomPopTransition: NSObject, UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.3
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
else {
return
}
let containerView = transitionContext.containerView
containerView.insertSubview(toViewController.view, belowSubview: fromViewController.view)
// Setup the initial view states
toViewController.view.frame = CGRect(x: -100, y: toViewController.view.frame.origin.y, width: fromViewController.view.frame.size.width, height: fromViewController.view.frame.size.height)
let dimmingView = UIView(frame: CGRect(x: 0,y: 0, width: toViewController.view.frame.width, height: toViewController.view.frame.height))
dimmingView.backgroundColor = UIColor.black
dimmingView.alpha = 0.5
toViewController.view.addSubview(dimmingView)
UIView.animate(withDuration: transitionDuration(using: transitionContext),
delay: 0,
options: UIView.AnimationOptions.curveLinear,
animations: {
dimmingView.alpha = 0
toViewController.view.frame = transitionContext.finalFrame(for: toViewController)
fromViewController.view.frame = CGRect(x: toViewController.view.frame.size.width, y: fromViewController.view.frame.origin.y, width: fromViewController.view.frame.size.width, height: fromViewController.view.frame.size.height)
},
completion: { finished in
dimmingView.removeFromSuperview()
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
}
)
}
}
PoppingNavigationController.swift
import UIKit
class PoppingNavigationController : UINavigationController, UINavigationControllerDelegate {
var interactivePopTransition: UIPercentDrivenInteractiveTransition!
override func viewDidLoad() {
self.delegate = self
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
addPanGesture(viewController: viewController)
}
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if (operation == .pop) {
return CustomPopTransition()
}
else {
return nil
}
}
func navigationController(navigationController: UINavigationController, interactionControllerForAnimationController animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
if animationController.isKind(of: CustomPopTransition.self) {
return interactivePopTransition
}
else {
return nil
}
}
func addPanGesture(viewController: UIViewController) {
let popRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanRecognizer(recognizer:)))
viewController.view.addGestureRecognizer(popRecognizer)
}
#objc
func handlePanRecognizer(recognizer: UIPanGestureRecognizer) {
// Calculate how far the user has dragged across the view
var progress = recognizer.translation(in: self.view).x / self.view.bounds.size.width
progress = min(1, max(0, progress))
if (recognizer.state == .began) {
// Create a interactive transition and pop the view controller
self.interactivePopTransition = UIPercentDrivenInteractiveTransition()
self.popViewController(animated: true)
}
else if (recognizer.state == .changed) {
// Update the interactive transition's progress
interactivePopTransition.update(progress)
}
else if (recognizer.state == .ended || recognizer.state == .cancelled) {
// Finish or cancel the interactive transition
if (progress > 0.5) {
interactivePopTransition.finish()
}
else {
interactivePopTransition.cancel()
}
interactivePopTransition = nil
}
}
}
Example of the result:
There really is no need to roll your own solution for this, sub-classing UINavigationController and referencing the built-in gesture works just fine as explained here.
The same solution in Swift:
public final class MyNavigationController: UINavigationController {
public override func viewDidLoad() {
super.viewDidLoad()
self.view.addGestureRecognizer(self.fullScreenPanGestureRecognizer)
}
private lazy var fullScreenPanGestureRecognizer: UIPanGestureRecognizer = {
let gestureRecognizer = UIPanGestureRecognizer()
if let cachedInteractionController = self.value(forKey: "_cachedInteractionController") as? NSObject {
let string = "handleNavigationTransition:"
let selector = Selector(string)
if cachedInteractionController.responds(to: selector) {
gestureRecognizer.addTarget(cachedInteractionController, action: selector)
}
}
return gestureRecognizer
}()
}
If you do this, also implement the following UINavigationControllerDelegate function to avoid strange behaviour at the root view controller:
public func navigationController(_: UINavigationController,
didShow _: UIViewController, animated _: Bool) {
self.fullScreenPanGestureRecognizer.isEnabled = self.viewControllers.count > 1
}
Subclassing the UINavigationController you can add a UISwipeGestureRecognizer to trigger the pop action:
.h file:
#import <UIKit/UIKit.h>
#interface CNavigationController : UINavigationController
#end
.m file:
#import "CNavigationController.h"
#interface CNavigationController ()<UIGestureRecognizerDelegate, UINavigationControllerDelegate>
#property (nonatomic, retain) UISwipeGestureRecognizer *swipeGesture;
#end
#implementation CNavigationController
#pragma mark - View cycles
- (void)viewDidLoad {
[super viewDidLoad];
__weak CNavigationController *weakSelf = self;
self.delegate = weakSelf;
self.swipeGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(gestureFired:)];
[self.view addGestureRecognizer:self.swipeGesture]; }
#pragma mark - gesture method
-(void)gestureFired:(UISwipeGestureRecognizer *)gesture {
if (gesture.direction == UISwipeGestureRecognizerDirectionRight)
{
[self popViewControllerAnimated:YES];
} }
#pragma mark - UINavigation Controller delegate
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
self.swipeGesture.enabled = NO;
[super pushViewController:viewController animated:animated]; }
#pragma mark UINavigationControllerDelegate
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animate {
self.swipeGesture.enabled = YES; }
#end

Resources