I am using REFrostedViewController as a side menu controller, the problem is this menu will appear from any point of screen, I want it to be like the Android version, which will appear only if you start swiping from the start left of screen, if swiping from any other point, the menu will not appear.
I want this because I am having a Page viewer inside this menu.
Since I am new in IOS, I looked inside the library code and didn't find any function that define the starting point also tried to modify the message
panGestureRecognized it didn't work .
So I'd like to suggest me a help or any other library that have the option.
If you have follow this Library then i think you have put this code too
In ViewDidLoad
[self.view addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureRecognized:)]];
And
- (void)panGestureRecognized:(UIPanGestureRecognizer *)sender
{
// Dismiss keyboard (optional)
//
[self.view endEditing:YES];
[self.frostedViewController.view endEditing:YES];
// Present the view controller
//
[self.frostedViewController panGestureRecognized:sender];
}
Replace Above code with below code.
Confirm UIGestureRecognizerDelegate Delegate protocol
#interface DEMONavigationController () <UIGestureRecognizerDelegate>
In ViewDidLoad
UIScreenEdgePanGestureRecognizer *leftEdgeGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:#selector(handleLeftEdgeGesture:)];
leftEdgeGesture.edges = UIRectEdgeLeft;
leftEdgeGesture.delegate = self;
[self.view addGestureRecognizer:leftEdgeGesture];}
And
- (void)handleLeftEdgeGesture:(UIScreenEdgePanGestureRecognizer *)gesture {
if(UIGestureRecognizerStateBegan == gesture.state ||
UIGestureRecognizerStateChanged == gesture.state) {
[self.frostedViewController presentMenuViewController];
}else{
// DO nothing
}
}
Related
Sorry for the long-winded explination, but this question - or something similar - has been asked a few times and I havent found a satisfactory answer. I am writing an iPad app in iOS 8 that implements UISplitViewController. Recently I have been attempting to get it to work on the iPhone. It transferred over pretty well, everything collapses automatically and a back button is included in the left side of my nav. bar.
My problem is that I want to keep the back button functionality to pop one view off the stack, but also be able to pan back to the primary view even if there are several detail views on top of it. Ideally, I want to be able to overwrite or redirect the interactivePopGestureRecognizer so that the gesture smoothly pans to the primary view (in some cases it can have anywhere from 1 to 4 detail views stacked on top of it). But, I cannot figure out how to do this.
My current solution (code below) is to disable the interactivePopGestureRecognizer in the detail viewcontroller and implement my own ScreenEdgePanGestureRecognizer that, when triggered, executes popToRootViewController. I've subclassed the ScreenEdgePanGestureRecognizer so it treats the screen edge pan as a discrete "swipe" (i.e. once a large enough screen edge swipe is detected - pop everything off the stack so the primary view is visible).
Code in detail view controller to stop interactivePopGestureRecognizer:
-(void)viewWillAppear : (BOOL) animated {
[super viewWillAppear : animated];
// stops navigation controller from responding to the default back swipe gesture
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled =NO;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
// Disable the default back swipe gesture tied to automatically included back button
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer isEqual:self.navigationController.interactivePopGestureRecognizer]) {
return NO;
} else {
return YES;
}
}
I didn't think it was necessary to include my subclass for the screenEdgePanGestureRecognizer because it has nothing to do with the solution I am asking about here is some pseudocode that shows what my #selector does in the detail viewcontroller:
- (IBAction)leftEdgeSwipe:(ScreenEdgeSwipeGestureRecognizer*)sender {
if (sender.swipeIsValid) {
[(UINavigationController *)self.splitViewController.viewControllers[0]
popToRootViewControllerAnimated:YES];
}
}
I tried to use the continuous pan, but cannot find a way to present the primary view in the background as I am pulling the current view aside to give that clean, smooth panning effect. I am able to make it so I can move the current view around, but there is just a grey background behind it where I would want my primary view to be.
Summation: If there is indeed no way to change the interactivePopGestureRecognizer to always jump to my primary view (ideal solution), then any info on how I can make my own smooth pan back to my primary view would be much appreciated.
So I have been messing around with making a smooth panning gesture subclass. Currently it functions similarly to Apple's back gesture except it jumps all the way back to the root view controller instead of popping one view off the stack. The only problem is that it does not yet show the primary view in the background while panning. I will update the answer once I get that worked out.
Here is the subclass:
#import <UIKit/UIKit.h>
#import <UIKit/UIGestureRecognizerSubclass.h>
#import "ScreenEdgeSwipeGestureRecognizer.h"
#interface ScreenEdgeSwipeGestureRecognizer ()
#property (nonatomic) UINavigationController* navController;
#end
#implementation ScreenEdgeSwipeGestureRecognizer{
CGPoint _screenCenter;
CGPoint _cumulativePanDistance;
}
- (id)initWithNavigationController:(UINavigationController*)navController {
self = [super initWithTarget:self action:#selector(leftEdgePan:)];
_screenCenter = CGPointZero;
_cumulativePanDistance = CGPointZero;
self.edges = UIRectEdgeLeft;
self.navController = navController;
return self;
}
- (IBAction)leftEdgePan:(ScreenEdgeSwipeGestureRecognizer*)sender {
assert(sender == self);
switch (self.state) {
case UIGestureRecognizerStateBegan:
[self initializePositions];
break;
case UIGestureRecognizerStateChanged:
[self updatePositions];
break;
case UIGestureRecognizerStateEnded:
[self animateViewBasedOnCurrentLocation];
break;
case UIGestureRecognizerStateCancelled:
[self animateViewToCenter];
break;
default:
break;
}
// Reset velocity of the pan so current velocity does not compound with velocity of next cycle
[sender setTranslation:CGPointMake(0, 0) inView:sender.view];
}
- (void)initializePositions {
_screenCenter = self.view.center;
_cumulativePanDistance = CGPointZero;
}
- (void)updatePositions {
// Track position of user touch event
CGPoint deltaSinceLastCycle = [self translationInView:self.view];
// View center = view center at last cycle + distance moved by user touch since last cycle
self.view.center=CGPointMake((self.view.center.x + deltaSinceLastCycle.x), self.view.center.y+ 0);
// Update the total positive distance traveled by the user touch event.
_cumulativePanDistance.x = _cumulativePanDistance.x + deltaSinceLastCycle.x;
}
- (void)animateViewBasedOnCurrentLocation {
if (_cumulativePanDistance.x >= (_screenCenter.x - 50)){
[self reset];
[_navController popToRootViewControllerAnimated:YES];
}else{
[self animateViewToCenter];
[self reset];
}
}
- (void)animateViewToCenter {
[UIView animateWithDuration:0.25 animations:^{self.view.center = self->_screenCenter;}];
}
- (void)reset {
[super reset];
_cumulativePanDistance = CGPointZero;
self.state = UIGestureRecognizerStatePossible;
}
#end
Here is how I instantiate the recognizer in my view controller:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Initialize the screen edge pan gesture recognizer.
_masterNavigationController = self.splitViewController.viewControllers[0];
ScreenEdgePanGestureRecognizer* edgePanRecognizer = [[ScreenEdgeSwipeGestureRecognizer alloc] initWithNavigationController:_masterNavigationController];
// Add recognizer to view this controller is bound to.
[self.view addGestureRecognizer:_edgePanRecognizer];
}
I want a pretty simple thing - in my top controller (which is navigation controller) to set up a tap gesture recognizer which will catch all the taps everywhere on the view. Currently when I tap on a button the system is not even thinking to bother my recognizer (except the gestureRecognizer:shouldReceiveTouch: delegate method, where I return YES). Instead, it just executes a button click. So I want to install "the strongest" recognizer on a view hierarchy no matter what.
You might try putting an empty UIView on top of all other views and add the UITapGestureRecognizer to it. We do something similar with help overlays. The biggest issue is figuring out how and when to ignore the touches so the underlying buttons get them when needed.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *b = [UIButton buttonWithType:UIButtonTypeInfoDark];
b.frame = CGRectMake(50,50, b.bounds.size.width, b.bounds.size.height );
[self.view addSubview:b];
UIView *invisibleView = [[UIView alloc] initWithFrame:self.view.bounds];
invisibleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[invisibleView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapHit:)]];
[self.view addSubview:invisibleView];
}
-(void)tapHit:(UITapGestureRecognizer*)tap {
NSLog( #"tapHit" );
}
#end
I have a UIView called myView on myViewController. I have a UIGestureRecognizer called swipeLeft (code below) that detects when a user swipes left on it.
The problem is: myViewController recognises the same gesture on the whole screen and performs another action. So I would like my app to perform myMethod when you swipeLeft in this particular area of myViewController, the area being myView.
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self
action:#selector(myMethod:)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
swipeLeft.delaysTouchesBegan = YES;
[self.myView addGestureRecognizer:swipeLeft];
More details: I am using RESideMenu and myViewController is the right menu, so when it is visible, the whole view of myViewController recognises swipes in all directions. I would like to change the recogniser in this particular UIView myView.
Thanks!
First you will need to add the swipe gesture to your view controllers header file.
#property (strong, nonatomic) UISwipeGestureRecognizer *swipeLeft;
If you look in DEMORootViewController.m, you will see this call:
self.rightMenuViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"rightMenuViewController"];
This will call your awakeFromNib, and it's your first chance to do something. In here you will create that swipe gesture. You can not add it to your view yet though, because your outlets are not set at this point. The first time they are set is in viewDidLoad, so that's where you will add the gesture to your view. So add this to your view controllers implementation file
- (void)awakeFromNib
{
self.swipeLeft = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(myMethod:)];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.swipeView addGestureRecognizer:self.swipeLeft];
}
- (void)myMethod:(UISwipeGestureRecognizer *)swipe
{
NSLog(#"Did swipe") ;
}
Finally you will need to tell the pan gesture in RESideMenu.m to fail whenever our swipeLeft gesture occurs. The way to do that is to add the following code to RESideMenu.m at line 220. That's at the end of the viewDidLoad method.
if ([self.rightMenuViewController isKindOfClass:[DEMOVC class]]) {
DEMOVC *rightVC = (DEMOVC *)self.rightMenuViewController;
if (rightVC.swipeLeft) {
[panGestureRecognizer requireGestureRecognizerToFail:rightVC.swipeGesture];
} } }
This is assuming your custom VC is called DEMOVC. You will also need to import your custom VC to RESideMenu.m like this:
#import "DEMOVC.h"
Please let me know if this worked out for you, and if there's something else I can help you with.
I am using SWRevealViewController in my app and I am having a problem. I have a textfield in a scene, if I swipe left when the keyboard is open, the menu appears but it does not dismiss the keyboard. How do I dismiss keyboard on left swipe?
I have tried
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
swipe.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeRecognizer];
-(void)dismissKeyboard
{
[self.textField resignFirstResponder];
}
but it does not work, I think because I am already using a panGestureRecognizer for revealViewcontroller i.e. [self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
I am also using UITapGestureRecognizer but it only works for tap not for swipe.
I had the same problem.
I added self.revealController.delegate = self; to my View Controller which I used as Front View.And delegate method get called.
I used
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position{}
delegate method and I wrote [textField endEditing:YES]; in this delegate method.
Also added <SWRevealViewControllerDelegate> to my ViewController.h which is my Front View.
i think u need to use one of the delegate method in the app delegate there are so may delegate methods are there but u need do somthing like below
dont add any gestures
use this delegate in the appDelegate
delete all the macros begins with #if don`t need that
put a break-point in app delegate to this method
below delegate method celled each time SWRevealViewController moved or sliced ..
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position
{
// NSLog( #"%#: %#", NSStringFromSelector(_cmd), [self stringFromFrontViewPosition:position]);
if(position == FrontViewPositionRight) //check the where to move
{
UINavigationController *viewController = revealController.frontViewController;
if([viewController.visibleViewController isKindOfClass:[FrontViewController class]])
{
[(FrontViewController *)viewController.visibleViewController dismissKeyboard]; //where this is the method declared in the FrontViewController.h file
}
}
}
there is one warning still it works put break point and check
hope this helps u ...
in FrontViewController.h
-(void)dismissKeyboard; //add this
in the FrontViewController.m
-(void)dismissKeyboard
{
if([self.textField isFirstResponder]) //check
[self.textField resignFirstResponder];
}
Try this:
Please add the below code in SWRevealViewContoller.m in the method -(BOOL)_panGestureShouldBegin
[self.view endEditing:YES];
First of all you need to replace the revealToggle: method by your custom method like this:
UIBarButtonItem *barBtn = [[UIBarButtonItem alloc]initWithImage:[UIImage imageNamed:#"reveal-icon.png"] style:UIBarButtonItemStyleBordered target:self action:#selector(myMethod)];
self.navigationItem.leftBarButtonItem = barBtn;
And than in your method:
-(void)myMethod{
[self.view endEditing:YES];
SWRevealViewController *reveal = self.revealViewController;
[reveal revealToggleAnimated:YES];
}
It will surely work.
Try This
[[[self revealViewController] view] endEditing:YES]
Add this in
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position
or any other delegate method based on your requirement.
check current position of frontview and write code of hiding keyboard in if condition.
Are you sure that self.textField is the current first responder? If you are try to resign the first responder in the UIGestureRecognizer delegate's method – gestureRecognizerShouldBegin:
Obviously return YES in that function.
Edit the below method in
SWRevealViewContoller.m
(IBAction)revealToggle:(id)sender {
[self.view endEditing:YES];
[self revealToggleAnimated:YES];
}
Is it possible to dismiss the keyboard when you have MULTIPLE UITextFields ? If so how ?
As a side note, do I have to dismiss the keyboard for Each and Every field or can it be done globally ? Oh and it would be super cool if I don't have to touch the DONE button, I'd ideally like a solution that where the user touches anything BUT the field in question and the keyboard automagically disappears...
Oh and if you'd be so kind step by step instructions.
I should have added that I have a method already to resign the keyboard....
However, it only runs when my form is submitted! (see method below)
My question is how to the keyboard to hide/dismiss without having to jump thru so many damned hoops! You'd figure after 6 years, a mature operating system would have a way to GLOBALLY hide the keyboard....NOT!
Ok, enough whining....
- (void)hideKeyboard {
[self.dancePlace resignFirstResponder];
[self.danceGate resignFirstResponder];
[self.danceTerminal resignFirstResponder];
[self.danceText resignFirstResponder];
[self.danceDate resignFirstResponder];
[self.danceStyle resignFirstResponder];
[self.danceTimeOut resignFirstResponder];
}
And this is called when my button is submitted....
- (IBAction)addListingPressed:(id)sender {
// NSLog(#"BUTTON PRESSED");
[self hideKeyboard];
[self valuesAdded];
}
My question, assuming anyone can answer this...and I suspect not, is there a way to globally hide the keyboard if the following conditions are MET: 1.) the user taps OUT of any one of the existing fields, 2.) presses anywhere else on the screen. 3.) Is no more than a line or two in the existing viewcontroller.m file. 4.) I don't have to add a confusing button on the viewcontroller. (any time I have to add outlets, the damned thing is crashing on me...and then nastiness happens, and really...remember I am JUST a beginner, and its very confusing to read that I have to place this here and that there...oy. Simple folks, simple. I'm not looking for elegant solution, just so that it works.
I have a super class that all my view controllers inherit from. In that class I have this code.
MySuperViewController.h
#import <UIKit/UIKit.h>
#interface MySuperViewController : UIViewController
#property(strong, nonatomic) UITapGestureRecognizer *backgroundTapGestureRecognizer;
#end
MySuperViewController.m
- (void)viewDidLoad{
//add a tap gesture recognizer to capture all tap events
//this will include tap events when a user clicks off of a textfield
self.backgroundTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(onBackgroundTap:)];
self.backgroundTapGestureRecognizer.numberOfTapsRequired = 1;
self.backgroundTapGestureRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:self.backgroundTapGestureRecognizer];
}
- (void)onBackgroundTap:(id)sender{
//when the tap gesture recognizer gets an event, it calls endEditing on the view controller's view
//this should dismiss the keyboard
[[self view] endEditing:YES];
}
I have the UITapGestureRecognizer as a public property, so I can override it if I need to.
subclass
MyViewController.h
#import <UIKit/UIKit.h>
#import "MySuperViewController.h"
#interface MyViewController : MySuperViewController<UIGestureRecognizerDelegate>
#end
MyViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//You don't always want the keyboard to be dismissed, so you tie into the gesture recognizer's delegate method
//By doing this, you can stop the endEditing call from being made
[self.backgroundTapGestureRecognizer setDelegate:self];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//touch.view is the view that recieved the touch
//if this view is another textfield or maybe a button, you can return NO and the endEditing call won't be made
if (touch.view == self.myViewThatShouldNotBeBlocked) {
return NO;
}
//if you want the gesture recognizer to accept the event, return yest
return YES;
}
I uploaded an example project to github.
https://github.com/JeffRegan/KeyboardBeGone
RDVKeyboardAvoiding is a scroll view with a tap gesture recognizer, designed for multiple textViews/textFields. It keeps track of the active view and removes a lot of boilerplate code.
tap anywhere outside the textField .. it will hide it..
[self.view endEditing:YES];
There are couple of other ways to do it.
[myEditField resignFirstResponder];
[myEditField endEditing];
[parentView endEditing];
If you dont wont to do so many things and simply want to dismiss keyboard than give iboutlet to each of your text filed to following method..
-(IBAction)hidekeyboard:(id)sender
{
[sender resignFirstResponder];
}
Yes, you only have to dismiss it for the one that is currently being edited.
In order to know which one is being edited, you can check the -(BOOL)isFirstResponder property, which will return YES if it is the first responder (the one being edited) or NO if it is not. Once you know which one is the first responder you can call -(void)resignFirstResponder on that one to get rid of the keyboard.
For example, if you have a method called -(void)aMethod that you want to dismiss the current view controller and you have an array of textViews called textArray, you could do a little loop such as:
-(void)aMethod {
for (UITextField *text in self.textArray) {
if ([text isFirstResponder]) [text resignFirstResponder];
return;
}
}
This way, you can have a variable number of textFields and it will still work.
If you only have one or two textFields and you do not want to create an Array object, you could do (assuming the fields are named text1 and text2:
-(void)aMethod {
if ([text1 isFirstResponder]) [text1 resignFirstResponder];
else if([text2 isFirstResponder]) [text2 resignFirstResponder];
}
Also, to make things easier for the future you could create a category method for UIView (which is what I do) to get the current first responder if it exists as a subview of that view:
#implementation UIView (GetFirstResponder)
- (UIView *)getFirstResponder {
if ([self isFirstResponder]) return self;
else {
for (UIView *subview in self.subviews) {
UIView *firstResponder = [subview getFirstResponder];
if (firstResponder) return firstResponder;
}
}
return nil;
}
You can put this method on the top of any file that you want to call it from, or create a separate file for it and import it.
Once you have this method, you can call:
- (void)aMethod {
UIView *view = [self.view getFirstResponder];
if (view) [view resignFirstResponder];
}
[superview endEditing:YES]; // superview can be the view controller's view property.