Right now I am using SWRevealViewController class in my project.
The basic functionality allows me to swap front view by pressing navigation bar button. But I want to add gesture to entire view.
I can add this code and it works for my button.
[self.startTestButton addGestureRecognizer:self.revealViewController.panGestureRecognizer];
But it just works for the one UI element. So I can't add, for example, other UI element to this gesture.
This code below shows how panGestureRecognizer method has been written:
- (UIPanGestureRecognizer*)panGestureRecognizer
{
if ( _panGestureRecognizer == nil )
{
SWDirectionPanGestureRecognizer *customRecognizer =
[[SWDirectionPanGestureRecognizer alloc] initWithTarget:self action:#selector(_handleRevealGesture:)];
customRecognizer.direction = SWDirectionPanGestureRecognizerHorizontal;
customRecognizer.delegate = self;
_panGestureRecognizer = customRecognizer ;
}
return _panGestureRecognizer;
}
To add the gesture recognizer to the whole view just add it to the whole view instead of just a single button. I'm using SWRevealViewController and my main view is a UITableView so to get the gesture recognizer to work on the whole view I have this in the viewDidLoad method of my UIViewController:
[self.tableView addGestureRecognizer: self.revealViewController.panGestureRecognizer];
So, just add the recognizer to the view you like. For most UIViewContollers this will be self.view.
Obviously if any controls or subviews of the view have their own gesture recognisers, these will take precedence of the one on the top level view, such that the panning will only work in the areas not occupied by those subviews.
//UPD:
Seems my previous solution is a overkill, you just could call getter to get the default behaviour. I.e.
[revealViewController panGestureRecognizer];
// old solution
You could also add SWRevealViewController's panGestureRecognizer to it's own view, for example in a subclass of SWRevealViewController you may have:
- (void)viewDidLoad
{
[super viewDidLoad];
// adds gesture recognizer to the whole thing
[self.view addGestureRecognizer:self.panGestureRecognizer];
}
If you're using a navigation controller and try to add the gesture recognizer to self.view, the gesture won't respond when swiping on the navigation bar. What I did was go into SWReaveal Classes and add a second gesture recognizer. So now I add one recognizer to self.view and one to the navigation bar. Works perfectly. I can share code if you need it but it shouldn't be too hard
To add Gesture on entire front view using SWRevealViewController using storyboard, we have to add
SWRevealViewController *revealController = [self revealViewController];
[revealController panGestureRecognizer];
[revealController tapGestureRecognizer];
in the the FirstViewController of the app. Add Action and Target to the Navigation bar button like
_sidebarButton.target = self.revealViewController;
_sidebarButton.action = #selector(revealToggle:);
// Set the gesture
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
In the SWRevealViewController.h add following method like
- (UITapGestureRecognizer*)tapGestureRecognizer;
- (BOOL)revealControllerTapGestureShouldBegin:(SWRevealViewController *)revealController;
In the SWRevealViewController.m add
- (UITapGestureRecognizer*)tapGestureRecognizer
{
if ( _tapGestureRecognizer == nil )
{
UITapGestureRecognizer *tapRecognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(_handleTapGesture:)];
tapRecognizer.delegate = self;
[_contentView.frontView addGestureRecognizer:tapRecognizer];
_tapGestureRecognizer = tapRecognizer ;
}
return _tapGestureRecognizer;
}
- (void)_handleTapGesture:(UITapGestureRecognizer *)recognizer
{
NSTimeInterval duration = _toggleAnimationDuration;
[self _setFrontViewPosition:FrontViewPositionLeft withDuration:duration];
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if ( _animationQueue.count == 0 )
{
if ( gestureRecognizer == _panGestureRecognizer )
// return [self _panGestureShouldBegin];
return ( gestureRecognizer == _panGestureRecognizer && _animationQueue.count == 0) ;
if ( gestureRecognizer == _tapGestureRecognizer )
return [self _tapGestureShouldBegin];
}
return NO;
}
In case of xib you can direct use
https://github.com/John-Lluch/SWRevealViewController
On Swift
self.revealViewController().frontViewController.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
If you are using a navigation controller for your front view you can add the pan gesture to the nav controller's view like this
[self.navigationController.view addGestureRecognizer: self.revealViewController.panGestureRecognizer];
That way you can also swipe on the navigation bar without altering any classes of the SWReveal controller.
Related
I am fairly new at programming in objective c and am trying to implement swipe gestures to swipe between view controllers on an app I am creating in xcode. I'm trying to make it so when I swipe left, it switches to another view controller that I have named "SecondViewController". I have created the outlet and action for my gesture in my .h file, and in my .m file I have added the following code:
- (IBAction)swipeLeft:(id)sender {
ViewController *SecondViewController = [[ViewController alloc] init];
[self presentViewController:SecondViewController animated:YES
completion:nil];
Whenever I run the app, nothing happens when I swipe. Is there something that I have not yet done that I need to do to make this work?
There are basically four Swipe Gesture is available:
UISwipeGestureRecognizerDirectionRight
UISwipeGestureRecognizerDirectionLeft
UISwipeGestureRecognizerDirectionUp
UISwipeGestureRecognizerDirectionDown
You can use any of it as per your requirement. To adding any of above gesture, you can alloc Gesture and then add it to your particular view. So as soon as you swipe detected, it will call relevant method.
For Example for Right and Left gesture:
UISwipeGestureRecognizer *gestureRecognizerRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandlerRight:)];
[gestureRecognizerRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.view addGestureRecognizer:gestureRecognizerRight];
UISwipeGestureRecognizer *gestureRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeHandlerLeft:)];
[gestureRecognizerLeft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[self.view addGestureRecognizer:gestureRecognizerLeft];
-(void)swipeHandlerRight:(id)sender
{
}
-(void)swipeHandlerLeft:(id)sender
{
}
I am using SWRevealViewController for sliding menu. I have added tap gesture in the front view using:
SWRevealViewController *revealController = [self revealViewController];
[revealController tapGestureRecognizer];
My tap gesture is working. But problem is that my front view has button which require the taps to navigate to other screens. IS there any way to disable the tap gesture when frontView is enabled and enable tap Gesture when menu is pressed?
I think you tried this
create the delegate on your class
#interface xxxViewController () <SWRevealViewControllerDelegate>
on delegate method as
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position
{
if (position == FrontViewPositionLeftSide) {
self.tapGestureRecognizer.enabled = YES;
// disable your current class action
}
else if (position == FrontViewPositionLeft){
self.tapGestureRecognizer.enabled = NO;
// enable your current class action
}
}
Import SWRevealViewController.h in your slide out menu class. Then in your sliding menu viewWillAppear method put this line-
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
self.revealViewController.frontViewController.revealViewController.tapGestureRecognizer.enabled=false;
}
and in viewWillDisappear method put this line-
-(void) viewWillDisappear:(BOOL)animated
{
self.revealViewController.frontViewController.revealViewController.tapGestureRecognizer.enabled=true;
}
In Front view controller add this
SWRevealViewController *objRevealViewController = [self revealViewController];
[self.view addGestureRecognizer:objRevealViewController.tapGestureRecognizer];
I have a LongPressGesture recogniser which when a long press is detected it presents a new segue:
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
[self performSegueWithIdentifier:#"showImage" sender:self];
}
The problem being i want the new 'segue' to detect that the gesture had ended and revert back to the previous view controller :
if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
[self presentViewController:friendViewController animated:YES completion:Nil];
}
I have tried to set up a new gesture recogniser in the new segue but it isn't detected unless the user ends the previous gesture.
You're doing (or trying to do) several things incorrectly. When you segue to the new controller, the long press recognizer's state will go to "failed", so there's nothing more you can do with it. There's no way to add a gesture recognizer to the new controller's view that will accept your previous touch as the beginning of its touch, so that's not going to work. Also, if you want to go back to your previous controller, you shouldn't use presentViewController, that just creates a new instance of friendViewController; it doesn't go back to the old one.
I think the way you need to accomplish your goal, is not to present a new controller, but to add a new view on top of the one with the gesture recognizer. In the example below, I just create a simple view for demonstration purposes, but you could create one in a xib if you need something more complicated.
-(IBAction)handleLongPress:(UILongPressGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {
UIView *newView = [[UIView alloc] initWithFrame:self.view.bounds];
newView.backgroundColor = [UIColor redColor];
newView.tag = 10;
[self.view addSubview:newView];
}
if (sender.state == UIGestureRecognizerStateEnded) {
[[self.view viewWithTag:10] removeFromSuperview];
}
}
How would I make it so that one gesture anywhere on a UITableView would do something?
Not just within one cell, but anywhere on the screen (a horizontal swipe)?
- (void)viewDidLoad
{
[super viewDidLoad];
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
//There is a direction property on UISwipeGestureRecognizer. You can set that to both right and left swipes
recognizer.direction = UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionLeft;
[tableView addGestureRecognizer:recognizer];
[recognizer release];
}
Finally
Just return UITableViewCellEditingStyleNone in your tableView:editingStyleForRowAtIndexPath: method.
If you want to make it dead simple using the interface builder you can apply the gesture on a ViewController that contains only the TableView and show that ViewController inside a container.
I have a simple UIViewController derived controller which has UITextFields.
Also using IB, I placed a UIToolbar and two UIBarButtonItems. I Ctrl-Drag to add actions to the buttons.
- (IBAction)cancel:(id)sender { ... }
- (IBAction)save:(id)sender { ... }
If I run the code, the actions get called.
The problem: I wanted to implement the tap on background to resignFirstResponder paradigm, so I added a UITapGestureRecognizer on the root view:
- (void)viewDidLoad {
...
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
When I have the gesture recognizer, the actions of the UIBarButtonItems are not called
How can I have it both ways?
Thanks for any explanations that could help me implement this.
I resolved the problem by adding another view and setting the gesture recognizer on that view instead of the root view.
But I still would like to know the explanation to why the gesture recognizer would "eat" the action of the UIBarButtonItem.