iOS Simulator Not Recognizing Gestures - objective-c

I am adding a UISwipeGestureRecognizer and a UITapGestureRecognizer to a view in a view controller's viewDidLoad method.
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addGestureRecognizer:[[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(cardSwipe:)]];
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(cardTap:)]];
}
- (void)cardSwipe:(UISwipeGestureRecognizer *)sender {
//get the card. set faceUp to false.
CGPoint location = [sender locationInView:sender.view];
NSIndexPath *cellIndex = [self.cardCollectionView indexPathForItemAtPoint:location];
if(cellIndex){
UICollectionViewCell *cell = [self collectionView:self.cardCollectionView cellForItemAtIndexPath:cellIndex];
if(cell && [cell isKindOfClass:[CardCollectionViewCell class]]){
[[((CardCollectionViewCell *)cell) cardView] handleCardSwipe];
}
}
}
- (void)cardTap:(UITapGestureRecognizer *)sender {
//get the card. set faceUp to false.
CGPoint location = [sender locationInView:sender.view];
NSIndexPath *cellIndex = [self.cardCollectionView indexPathForItemAtPoint:location];
if(cellIndex){
UICollectionViewCell *cell = [self collectionView:self.cardCollectionView cellForItemAtIndexPath:cellIndex];
if(cell && [cell isKindOfClass:[CardCollectionViewCell class]]){
[[((CardCollectionViewCell *)cell) cardView] handleCardSwipe];
}
}
}
In case this is relevant: The view contains a UICollectionView.
The taps and swipes are not getting recognized. Is there something obvious that I am missing?
Thanks.

Restarting the simulator worked for me.

Turns out the view was not responding to any gestures - scrolling, taps on buttons or the swipe actions. I deleted generated folders from ~/Library/Application Support/iPhone Simulator / 6.1/Applications and ~/Library/Developer/Xcode/DerivedData, reset the simulator settings (from iOS Simulator > Reset Contents and Settings), did a clean in xcode (Product > Clean) and ran the app again. The gestures are now recognized. I am not sure which of the above fixed the problem...it is possible that simply resetting the simulator's contents and settings would have been enough.

You just need to select Show Device Bezels:
Goto simulator > Window > Enable Show Device Bezels
Enjoy your swipe to back gesture.

add this method to your viewcontroller so your UICollectionView doesn't block other gestures
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return true;
}

In case you have already enabled Device Bezels from Window panel but still can't use swipe to go back gesture. Please refer to this answer.
All you need to do is restart the simulator and try to swipe from the real edge of the simulator.

First you Need To Add UITapGestureRecognizer Delegate method To .h
#interface ViewController : UIViewController<UIGestureRecognizerDelegate>
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doubleTapImgView:)];
doubleTap.numberOfTapsRequired = 2;
doubleTap.delegate = self;
- (void)doubleTapImgView:(UITapGestureRecognizer *)gesture
{
//Do What you want Here
}

Related

How to set size for popover? [duplicate]

I have a UIPopoverController hosting a UINavigationController, which contains a small hierarchy of view controllers.
I followed the docs and for each view controller, I set the view's popover-context size like so:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
(size different for each controller)
This works as expected as I navigate forward in the hierarchy-- the popover automatically animates size changes to correspond to the pushed controller.
However, when I navigate "Back" through the view stack via the navigation bar's Back button, the popover doesn't change size-- it remains as large as the deepest view reached. This seems broken to me; I'd expect the popover to respect the sizes that are set up as it pops through the view stack.
Am I missing something?
Thanks.
I was struggling with the same issue. None of the above solutions worked for me pretty nicely, that is why I decided to do a little investigation and find out how this works.
This is what I discovered:
When you set the contentSizeForViewInPopover in your view controller it won't be changed by the popover itself - even though popover size may change while navigating to different controller.
When the size of the popover will change while navigating to different controller, while going back, the size of the popover does not restore
Changing size of the popover in viewWillAppear gives very strange animation (when let's say you popController inside the popover) - I'd not recommend it
For me setting the hardcoded size inside the controller would not work at all - my controllers have to be sometimes big sometimes small - controller that will present them have the idea about the size though
A solution for all that pain is as follows:
You have to reset the size of currentSetSizeForPopover in viewDidAppear. But you have to be careful, when you will set the same size as was already set in field currentSetSizeForPopover then the popover will not change the size. For this to happen, you can firstly set the fake size (which will be different than one which was set before) followed by setting the proper size. This solution will work even if your controller is nested inside the navigation controller and popover will change its size accordingly when you will navigate back between the controllers.
You could easily create category on UIViewController with the following helper method that would do the trick with setting the size:
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
Then just invoke it in -viewDidAppear of desired controller.
Here's how I solved it for iOS 7 and 8:
In iOS 8, iOS is silently wrapping the view you want in the popover into the presentedViewController of the presentingViewController view controller. There's a 2014 WWDC video explaining what's new with the popovercontroller where they touch on this.
Anyways, for view controllers presented on the navigation controller stack that all want their own sizing, these view controllers need (under iOS 8) to call this code to dynamically set the preferredContentSize:
self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);
Replace heightOfTable with your computed table or view height.
In order to avoid a lot of duplicate code and to create a common iOS 7 and iOS 8 solution, I created a category on UITableViewController to perform this work when viewDidAppear is called in my tableviews:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self setPopOverViewContentSize];
}
Category.h:
#import <UIKit/UIKit.h>
#interface UITableViewController (PreferredContentSize)
- (void) setPopOverViewContentSize;
#end
Category.m:
#import "Category.h"
#implementation UITableViewController (PreferredContentSize)
- (void) setPopOverViewContentSize
{
[self.tableView layoutIfNeeded];
int heightOfTable = [self.tableView contentSize].height;
if (heightOfTable > 600)
heightOfTable = 600;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0)
self.preferredContentSize=CGSizeMake(320, heightOfTable);
else
self.presentingViewController.presentedViewController.preferredContentSize = CGSizeMake(320, heightOfTable);
}
}
#end
This is an improvement on krasnyk's answer.
Your solution is great, but it isn't smoothly animated.
A little improvement gives nice animation:
Remove last line in the - (void) forcePopoverSize method:
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
}
Put [self forcePopoverSize] in - (void)viewWillAppear:(BOOL)animated method:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self forcePopoverSize];
}
And finally - set desired size in - (void)viewDidAppear:(BOOL)animated method:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
You need to set the content size again in viewWillAppear. By calling the delagate method in which you set the size of popovercontroller. I had also the same issue. But when I added this the problem solved.
One more thing: if you are using beta versions lesser than 5. Then the popovers are more difficult to manage. They seem to be more friendly from beta version 5. It's good that final version is out. ;)
Hope this helps.
In the -(void)viewDidLoad of all the view controllers you are using in navigation controller, add:
[self setContentSizeForViewInPopover:CGSizeMake(320, 500)];
I reset the size in the viewWillDisappear:(BOOL)animated method of the view controller that is being navigated back from:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
CGSize contentSize = [self contentSizeForViewInPopover];
contentSize.height = 0.0;
self.contentSizeForViewInPopover = contentSize;
}
Then when the view being navigated back to appears, I reset the size appropriately:
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
CGSize contentSize;
contentSize.width = self.contentSizeForViewInPopover.width;
contentSize.height = [[self.fetchedResultsController fetchedObjects] count] * self.tableView.rowHeight;
self.contentSizeForViewInPopover = contentSize;
}
For iOS 8 the following works:
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.preferredContentSize;
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
self.preferredContentSize = fakeMomentarySize;
self.navigationController.preferredContentSize = fakeMomentarySize;
self.preferredContentSize = currentSetSizeForPopover;
self.navigationController.preferredContentSize = currentSetSizeForPopover;
}
BTW I think, this should be compatible with previous iOS versions...
Well i worked out. Have a look.
Made a ViewController in StoryBoard. Associated with PopOverViewController class.
import UIKit
class PopOverViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.preferredContentSize = CGSizeMake(200, 200)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:")
}
func dismiss(sender: AnyObject) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
See ViewController:
//
// ViewController.swift
// iOS8-PopOver
//
// Created by Alvin George on 13.08.15.
// Copyright (c) 2015 Fingent Technologies. All rights reserved.
//
import UIKit
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
{
func showPopover(base: UIView)
{
if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController {
let navController = UINavigationController(rootViewController: viewController)
navController.modalPresentationStyle = .Popover
if let pctrl = navController.popoverPresentationController {
pctrl.delegate = self
pctrl.sourceView = base
pctrl.sourceRect = base.bounds
self.presentViewController(navController, animated: true, completion: nil)
}
}
}
override func viewDidLoad(){
super.viewDidLoad()
}
#IBAction func onShow(sender: UIButton)
{
self.showPopover(sender)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
}
Note: The func showPopover(base: UIView) method should be placed before ViewDidLoad. Hope it helps !
For me this solutions works.
This is a method from my view controller which extends UITableViewController and is the root controller for UINavigationController.
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.contentSizeForViewInPopover = self.tableView.bounds.size;
}
And don't forget to set content size for view controller you gonna push into navigation stack
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
dc = [[DetailsController alloc] initWithBookmark:[[bookmarksArray objectAtIndex:indexPath.row] retain] bookmarkIsNew:NO];
dc.detailsDelegate = self;
dc.contentSizeForViewInPopover = self.contentSizeForViewInPopover;
[self.navigationController pushViewController:dc animated:YES];
}
if you can imagine the assambler, I think this is slightly better:
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.contentSizeForViewInPopover;
self.contentSizeForViewInPopover = CGSizeMake(0, 0);
self.contentSizeForViewInPopover = currentSetSizeForPopover;
}
The accepted answer is not working fine with iOS 8. What I did was creating my own subclass of UINavigationController for use in that popover and override the method preferredContentSize in this way:
- (CGSize)preferredContentSize {
return [[self.viewControllers lastObject] preferredContentSize];
}
Moreover, instead of calling forcePopoverSize (method implemented by #krasnyk) in viewDidAppear I decided to set a viewController (which shows popover) as a delegate for previously mentioned navigation (in popover) and do (what force method does) in:
-(void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
delegate method for a passed viewController. One important thing, doing forcePopoverSize in a UINavigationControllerDelegate method is fine if you do not need that animation to be smooth if so then do leave it in viewDidAppear.
I was facing same problem, but you don't want to set contentsize in viewWillAppear or viewWillDisappear method.
AirPrintController *airPrintController = [[AirPrintController alloc] initWithNibName:#"AirPrintController" bundle:nil];
airPrintController.view.frame = [self.view frame];
airPrintController.contentSizeForViewInPopover = self.contentSizeForViewInPopover;
[self.navigationController pushViewController:airPrintController animated:YES];
[airPrintController release];
set contentSizeForViewInPopover property for that controller before pushing that controller to navigationController
I've had luck by putting the following in the viewdidappear:
[self.popoverController setPopoverContentSize:self.contentSizeForViewInPopover animated:NO];
Although this may not animate nicely in the case when you're pushing/popping different-sized popovers. But in my case, works perfectly!
All that you have to do is:
-In the viewWillAppear method of the popOvers contentView, add the snippet given below. You will have to specify the popOver's size first time when it is loaded.
CGSize size = CGSizeMake(width,height);
self.contentSizeForViewInPopover = size;
I had this issue with a popover controller whose popoverContentSize = CGSizeMake(320, 600) at the start, but would get larger when navigating through its ContentViewController (a UINavigationController).
The nav controller was only pushing and popping custom UITableViewControllers, so in my custom table view controller class's viewDidLoad i set self.contentSizeForViewInPopover = CGSizeMake(320, 556)
The 44 less pixels are to account for the Nav controller's nav bar, and now I don't have any issues anymore.
Put this in all view controllers you are pushing inside the popover
CGSize currentSetSizeForPopover = CGSizeMake(260, 390);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f,
currentSetSizeForPopover.height - 1.0f);
self.contentSizeForViewInPopover = fakeMomentarySize;
self.contentSizeForViewInPopover = currentSetSizeForPopover;
Faced the same issue and fixed it by setting content view size to navigation controller and view controller before the init of UIPopoverController was placed.
CGSize size = CGSizeMake(320.0, _options.count * 44.0);
[self setContentSizeForViewInPopover:size];
[self.view setFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
[navi setContentSizeForViewInPopover:size];
_popoverController = [[UIPopoverController alloc] initWithContentViewController:navi];
I'd just like to offer up another solution, as none of these worked for me...
I'm actually using it with this https://github.com/nicolaschengdev/WYPopoverController
When you first call your popup use this.
if ([sortTVC respondsToSelector:#selector(setPreferredContentSize:)]) {
sortTVC.preferredContentSize = CGSizeMake(popoverContentSortWidth,
popoverContentSortHeight);
}
else
{
sortTVC.contentSizeForViewInPopover = CGSizeMake(popoverContentSortWidth,
popoverContentSortHeight);
}
Then in that popup use this.
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
if ([self respondsToSelector:#selector(setPreferredContentSize:)]) {
self.preferredContentSize = CGSizeMake(popoverContentMainWidth,
popoverContentMainheight);
}
else
{
self.contentSizeForViewInPopover = CGSizeMake(popoverContentMainWidth,
popoverContentMainheight);
}
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:YES];
self.contentSizeForViewInPopover = CGSizeZero;
}
Then repeat for child views...
This is the correct way in iOS7 to do this,
Set the preferred content size in viewDidLoad in each view controller in the navigation stack (only done once). Then in viewWillAppear get a reference to the popover controller and update the contentSize there.
-(void)viewDidLoad:(BOOL)animated
{
...
self.popoverSize = CGSizeMake(420, height);
[self setPreferredContentSize:self.popoverSize];
}
-(void)viewWillAppear:(BOOL)animated
{
...
UIPopoverController *popoverControllerReference = ***GET REFERENCE TO IT FROM SOMEWHERE***;
[popoverControllerReference setPopoverContentSize:self.popoverSize];
}
#krasnyk solution worked well in previous iOS versions but not working in iOS8. The following solution worked for me.
- (void) forcePopoverSize {
CGSize currentSetSizeForPopover = self.preferredContentSize;
//Yes, there are coupling. We need to access the popovercontroller. In my case, the popover controller is a weak property in the app's rootVC.
id mainVC = [MyAppDelegate appDelegate].myRootVC;
if ([mainVC valueForKey:#"_myPopoverController"]) {
UIPopoverController *popover = [mainVC valueForKey:#"_myPopoverController"];
[popover setPopoverContentSize:currentSetSizeForPopover animated:YES];
}
}
It is not the best solution, but it works.
The new UIPopoverPresentationController also has the resizing issue :( .
You need to set the preferredContentSizeproperty of the NavigationController in viewWillAppear:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.preferredContentSize = CGSizeMake(320, 500);}

Pop up UIViewController with an IBAction UIViewController

Is it possible to pop up an UIViewController (xib file) like UIPopOverControl in iPad ?
I have a separate NIB file which is linked to an UIViewController. I want to popup that NIB file along with the button pressed with a customised size (200,200).
Is this possible?
I am trying to get something like this on the iPhone - http://www.freeimagehosting.net/c219p
You can also use one of these custom made clases to show a popup:
https://github.com/sonsongithub/PopupView
https://github.com/werner77/WEPopover
https://github.com/50pixels/FPPopover
Example with FPPopover:
//the view controller you want to present as popover
YourViewController *controller = [[YourViewController alloc] init];
//our popover
FPPopoverController *popover = [[FPPopoverController alloc] initWithViewController:controller];
//the popover will be presented from the okButton view
[popover presentPopoverFromView:okButton];
//release if you arent using ARC
[controller release];
yes it is. load Your pOpOver controller lazily at the point when it is needed. add its view as a subview (you could animate the addition). make its frame size what You need and add the image You have shown as a background subview of the pOpOver controller along with other controls You want in the pop up.
good luck
UPDATE:
alright, ii will show You how ii do this in my app Lucid Reality Check (deployment target iOS4.3).
one can use a UIPopoverController to present another controllers view. what ii do first is to make sure ii always know the current orientation of the device, so ii can reposition the popup on rotation (maybe this works by itself on iOS6?). so in my base controller (from where ii want to show a popup) ii have an instance variable like this:
UIInterfaceOrientation toOrientation;
and also:
UIPopoverController *popover;
UIButton *popover_from_button;
BOOL representPopover;
popover will be reused for all popups, and popover_from_button will hold the button from which the popup is initiated.
then the next code comes into the base controller:
- (void)popoverWillRotate {
if ([popover isPopoverVisible]) {
[self dismissPopover];
representPopover = YES;
}
}
- (void)popoverDidRotate {
if (popover && representPopover) {
representPopover = NO;
[self representPopover];
}
}
these two methods have to be called every time the device is rotated, like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
//DLOG(#"willRotateTo %i", toInterfaceOrientation);
toOrientation = toInterfaceOrientation;
if ([Kriya isPad ]) {
[self popoverWillRotate];
}
}
as one can see, first the orientation is captured then popoverWillRotate is called. this would hide the popover during the orientation animation. and after rotating, the popover must be redisplayed like this:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
//DLOG(#"didRotateFrom %i", fromInterfaceOrientation);
//[self layout:toOrientation]; //do some layout if You need
if ([Kriya isPad]) {
[self popoverDidRotate];
}
}
- (void)layout:(UIInterfaceOrientation)toInterfaceOrientation {
//one can do view layout here, and call other controllers to do their layout too
}
now that the orientation changes are worked out, the code for presenting the popover arrives here:
#pragma mark Popovers
- (void)presentPopoverWith:(id)controller fromButton:(UIButton*)button {
if (popover)
[popover release];
if (popover_from_button)
[popover_from_button release];
popover_from_button = [button retain];
popover = [[UIPopoverController alloc] initWithContentViewController:controller];
[popover setDelegate:self];
[self representPopover];
}
- (void)representPopover{
if (popover) {
UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
UIViewController *vc = (UIViewController*)[popover contentViewController];
CGSize contentSize = [vc contentSizeForViewInPopover];
if (contentSize.width > 0 && contentSize.height > 0) {
[popover setPopoverContentSize:contentSize animated:NO];
}
//DLOG(#"representPopover rect:%#", [Kriya printRect:popover_from_button.frame]);
[popover presentPopoverFromRect:CGRectOffset(popover_from_button.frame, 0, popover_from_button.frame.size.height + 7.0) inView:self.view permittedArrowDirections:arrowDirection animated:YES];
}
}
- (void)dismissPopover {
if (popover) {
[popover dismissPopoverAnimated:YES];
}
}
finally, if one wants to be notified when the popover is dismissed, the base controller must implement a delegate method:
#pragma mark UIPopoverControllerDelegate
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
//do something important here like drink some water
}
and don't forget to make the base controller a UIPopoverControllerDelegate in its header.
a use case for this way of doing popups would then look like this:
- (void)takeImage {
UIImagePickerController *picker = [[[UIImagePickerController alloc] init] autorelease];
[picker setDelegate:self];
[picker setAllowsEditing:NO];
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[picker setSourceType:UIImagePickerControllerSourceTypeCamera];
if ([Kriya isPad]) {
[self presentPopoverWith:picker fromButton:backgroundImageButton];
} else {
//modals on iPhone/iPod
//DLOG(#"takeImage addSubview picker");
[self presentModalViewController:picker animated:YES];
}
} else {
//DLOG(#"no camera");
}
}
this would use an image picker as the content for the popup, but one can use any controller with a valid view. so just do this:
[self presentPopoverWith:popupsContentController fromButton:tappedButton];
one should not have any missing information, :), the method [Kriya isPad] is just this:
+ (BOOL)isPad {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
// iPad capable OS
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
//this is an iPad
return YES;
}else {
//this is an iPod/iPhone
return NO;
}
#else
//can not pissible be iPad
return NO;
#endif
}
ENJOY!

Multiple UITextFields in a custom UITableViewCell

I have a UITableView that has 2 different customcell definitions. One is a single UITextField and the other has 4 UITextFields
userInteractionEnabled is manually set to enable cell level touch navigation, and I handle the UI interaction within didSelectRowAtIndexPath to the first responder to the relevant cell
This all worked fine when I was using just the one customcell (EditableCustomCell) with one UITextField (editableTextField), but now I have a customcell (LatLonCustomCell) with 4 UITextFields (degrees, minutes, seconds, cartesian), I cannot determine which field has been touched in order to set becomeFirstResponder
(currently I'm defaulting in the first textfield called degrees during debug)
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[prevField resignFirstResponder];
prevField.userInteractionEnabled = NO;
if(indexPath.section == kFirstSection && (indexPath.row == kLatitudeRow || indexPath.row == kLongitudeRow)) {
LatLonCustomCell *customCell = (LatLonCustomCell *)[MyTableView cellForRowAtIndexPath:indexPath];
currField = customCell.degrees; // need to set correct field here
} else {
EditableCustomCell *customCell = (EditableCustomCell *)[MyTableView cellForRowAtIndexPath:indexPath];
currField = customCell.editableTextField;
}
currFieldIndexPath = [NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
currField.userInteractionEnabled = YES;
[currField becomeFirstResponder];
}
OK, so for those that come across this with the same or similar problem, I have finally made a breakthrough
I decided that I was going to need to capture the X/Y coordinates of the touch prior to the didSelectRowAtIndexPath being called. This way I could then determine which UITextField the touch occurred in by checking the touch against the "bounds" of the textfield
After some random searching, I found that a VERY easy way of capturing ANY touch event in the viewcontroller (as touchesBegan only occurred in the custom overridden UITableViewCell class and I knew not how to pass this back up the chain Cell > TableView > Scroll View > Controller)
By adding this to the viewDidLoad method:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 1;
// Pass the tap through to the UITableView
tapGesture.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:tapGesture];
This captures all touches, calling the handleTapGesture method
Then within this method it was simply a case of checking if the touch was within the bounds of the tableview, and if so, determine the indexPath for the point touched and then check against the bounds of the object required, below is a simplified version of what I came up with
-(void)handleTapGesture:(UITapGestureRecognizer *)tapGesture {
CGPoint tapLoc = [tapGesture locationInView:self.tableView];
if([MyTableView indexPathForRowAtPoint:tapLoc]) {
// Tap still handled by the UITableView delegate method
NSIndexPath *indexPath = [MyTableView indexPathForRowAtPoint:tapLoc];
if(indexPath.section == 0 && (indexPath.row == kLatitudeRow || indexPath.row == kLongitudeRow)) {
LatLonCustomCell *customCell = (LatLonCustomCell *)[MyTableView cellForRowAtIndexPath:indexPath];
UIScrollView *scrollView = (UIScrollView *)self.view;
CGRect rc;
// Degrees
rc = [customCell.degrees convertRect:[customCell.degrees bounds] toView:scrollView];
if (tapLoc.x >= rc.origin.x && tapLoc.y >= rc.origin.y && tapLoc.x <= (rc.origin.x + rc.size.width) && tapLoc.y <= (rc.origin.y + rc.size.height)) {
NSLog(#"touch within bounds for DEGREES");
touchField = customCell.degrees;
}
// Repeat for other textfields here ....
....
In my code I save the field within touchField, as within the didSelectRowAtIndexPath code, I am already handling prevField/currField values to control the enabling/disabling of userInteractionEnabled and to set the currField as becomeFirstReponder
Hope this proves helpful to someone :)
In the past when I have needed to check if a text box has been touched I checked if YourTextField.text.length > 0. If it is you can set becomeFirstResponder. Hope this helps.
Have you thought about using NSNotificationCenter to request notifications for UITextFieldTextDidBeginEditingNotification?
in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(textFieldBeganEditing)
name:UITextFieldTextDidBeginEditingNotification object:nil];
and then something like
-(void) textFieldBegainEditing: (NSNotification*) notification {
// [notification object] will be the UITextField
// do what you need to do with it (resign, become first responder)
}

keyboard resigning reduces popover height

I have a strange issue on ios 4.3.I have one of my screen in landscape mode, a button click presents a popover.My popover has a search bar.Whenever keyboard appears it automatically pushes my popover bit up.When I resign the keyboard , popover reduces in height.This is the issue only on ios 4.3.While in rest of the ios , my popover doesnot reduces in height after keyboard dismissal.
None of the answers above worked for me. Apparently the keyboard scales the view and restores this scaling after the UIKeyboardDidHideNotification notification, making the presentPopoverFromRect method useless when applied handling this notification.
The way I solved it was by delaying the latter call as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
popup = nil; //my ViewController with UITextField
popover = nil; //my UIPopoverController
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(resizePopup:)
name:UIKeyboardDidHideNotification
object:nil];
}
- (void)doDelayedResize
{
[popover presentPopoverFromRect:myButton.bounds inView:myButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (void)resizePopup:(NSNotification*)note
{
[self performSelector:#selector(doDelayedResize) withObject:nil afterDelay:0.01];
}
I answered a very similar question here: UIPopoverController's view controller gets resized after keyboard disappears
The way I got around it was to observe the keyboard disappearing in the controller which controls the UIPopoverController:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(presentSearchPopover) name:UIKeyboardDidHideNotification object:nil];
And then in -presentSearchPopover, present the UIPopoverController again (it's quite a seamless transition):
- (void)presentSearchPopover
{
self.searchPopoverController.popoverContentSize = CGSizeMake(width, height));
[self.searchPopoverController presentPopoverFromRect:someRect) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Don't forget to remove the observer in -dealloc or similar too:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];
[super dealloc];
}
I found an answer for this.It was a bug with the top arrow of popover.If I use the left arrow direction for popover, everything works fine.
I ran into this issue as well - specifically, the popover wasn't growing back to its pre-keyboard size after tapping away from the popover. (The popover would grow back if the user dismissed the keyboard directly or the popover's view controller resigned first responder).
Unfortunately, I have to use the top arrow direction for the popover due to the UI's layout. To solve this, the view controller responsible for the popover implements - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController. For example:
#interface MyController : UIViewController <UIPopoverControllerDelegate>
{
// ...
}
//...
#end
Set that controller as the popover's delegate:
MyPopoverViewController *popoverVC = [[MyPopoverViewController alloc] init];
UIPopoverController *myPopover = [[UIPopoverController alloc] initWithContentViewController:popoverVC];
myPopover.delegate = self;
// Hang on to popoverVC, myPopover or release them as desired...
In addition, my popover's view controller sets its contentSizeForViewInPopover property to the desired size:
#implementation MyPopoverViewController
- (id)init
{
self = [super init];
if (self)
{
// ...
self.contentSizeForViewInPopover = CGSizeMake(320, 400); // desired size
}
return self;
}
When the keyboard causes the popover to shrink, it affects the popover's popoverContentSize and not its view controller's contentSizeForViewInPopover. Therefore, reset popoverContentSize in MyController's delegate method:
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
// Check if popoverController is valid, the popover you want, etc
popoverController.popoverContentSize = popoverController.contentViewController.contentSizeForViewInPopover;
}
Here is my solution:
1. Register for keyboard Notifications (UIKeyboardWillShowNotification, UIKeyboardWillHideNotification)
2. Create local variables:
CGSize _currentPopoverContentSize; //if you want to have custom size for popover
UIView *_currentPopoverSender; //to remember from wich view you will present popover
BOOL _keyboardIsShown; //enable in keyboardWillShow, and disable in keyboardWillHide
3. In my presentPopover method:
- (void)presentPopoverControllerWithSize:(CGSize)size fromView:(UIView *)sender{
MyController *controller = [[[MyController alloc] init] autorelease];
if (self.popover)
{
[_popover release];
_popover = nil;
}
_popover = [[UIPopoverController alloc] initWithContentViewController:controller];
_popover.popoverContentSize = size;
_popover.delegate = self;
//checking if keyboard is shown - if NO, than present popover, if YES - just `resignFirstResponder` for your _`activeTextField`(you can set it in -textFieldDidBeginEditing: and nullify in -textFieldDidEndEditing:)
if (!_keyboardIsShown)
{
[_popover presentPopoverFromRect:[sender bounds]
inView:sender
permittedArrowDirections:UIPopoverArrowDirectionUp
animated:YES];
}
else
{
[_activeTextField resignFirstResponder];
}
_currentPopoverContentSize = size;
_currentPopoverSender = sender;
}
4. Than:
- (void)keyboardWillBeHidden:(NSNotification*)aNotification{
[UIView animateWithDuration:0.3
animations:^{
//do some stuff
[self.scrollView setContentSize:_scrollViewContentSize];
} completion:^(BOOL finished) {
if (_popover && _currentPopoverSender)
{
[_popover presentPopoverFromRect:[_currentPopoverSender bounds]
inView:_currentPopoverSender
permittedArrowDirections:UIPopoverArrowDirectionUp
animated:YES];
}
}];
_keyboardIsShown = NO;
}
Hi After going through the forum, I don't think it's a bug after playing with frame sizes a lot, working on IOS 4,5,6,7 it's the same behaviour.
The solution for me was to:
1) Go into the designer by
2) Opening the XIB ViewController that is causing the problem (i.e. the PopOver one).
3) Click to select it's VIEW.
4) Uncheck "AutoResizeSubviews"
5) When loading the PopOver in code, make sure you do:
6) Your_Popup_Window.popoverContentSize = Your_ViewController.view.bounds.size;
I hope this helps.
Kind Regards
Heider Sati

ViewForAnnotation is not being called

I am trying to make a map, where I can see my current location, and see what the street is called.
so far, I am able to put a pin on my map, but for some reason, I am not getting the callout.
and I have put a NSLog in my viewForAnnotation method, but it is not being called, so i wasn't able to test it.
can someone help me?
-(void)lat:(float)lat lon:(float)lon
{
CLLocationCoordinate2D location;
location.latitude = lat;
location.longitude = lon;
NSLog(#"Latitude: %f, Longitude: %f",location.latitude, location.longitude);
//One location is obtained.. just zoom to that location
MKCoordinateRegion region;
region.center=location;
//Set Zoom level using Span
MKCoordinateSpan span;
span.latitudeDelta=.005f;
span.longitudeDelta=.005f;
region.span=span;
[map setRegion:region animated:TRUE];
//MKReverseGeocoder *geocoder=[[MKReverseGeocoder alloc] initWithCoordinate:location];
//geocoder.delegate=self;
//[geocoder start];
if (cPlacemark != nil) {
[map removeAnnotation:cPlacemark];
}
cPlacemark=[[CustomPlacemark alloc] initWithCoordinate:location];
cPlacemark.title = mPlacemark.thoroughfare;
cPlacemark.subtitle = mPlacemark.locality;
[map addAnnotation:cPlacemark];
[cPlacemark release];
[mLocationManager stopUpdatingLocation];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
// try to dequeue an existing pin view first
if ([annotation isKindOfClass:[CustomPlacemark class]]){
MKPinAnnotationView *pinView=(MKPinAnnotationView *)[map dequeueReusableAnnotationViewWithIdentifier:#"customIdentifier"];
if (!pinView)
{
// if an existing pin view was not available, create one
MKPinAnnotationView* cPinAnnoView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:#"customIdentifier"] autorelease];
cPinAnnoView.pinColor = MKPinAnnotationColorPurple;
cPinAnnoView.animatesDrop = YES;
cPinAnnoView.canShowCallout = YES;
// Add button
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[leftButton addTarget:self action:#selector(annotationViewClick:) forControlEvents:UIControlEventTouchUpInside];
cPinAnnoView.leftCalloutAccessoryView = leftButton;
} else
{
pinView.annotation = annotation;
}
return pinView;
}
return nil;
}
Right now I have customized my viewForAnnotation to be like this.
But I still can't get a callout from my pin and the pin remains red.
But it should be purple of nothing at all
I had the same problem which was not setting the MapView delegate to the File Owner.
Open your nib
Right click on the MapView
Drag the delegate to the File's Owner
I had the same problem, as you mentioned. The delegate had been set to ViewController, but the viewForAnnotation selector was not being called. After some checks, I realized if you do not call addAnotation in the main thread, mapView would not call viewForAnnotation, so following update resolved my problem:
Before:
[_mMapView addAnnotation:marker];
After:
dispatch_async(dispatch_get_main_queue(), ^{
[_mMapView addAnnotation:marker];
});
In order to get the viewForAnnotation to be called, add mapView.delegate=self; to e.g. the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
mapView.delegate=self;
}
Could it be that your annotation has been added outside the current view area of the MKMapView?
For storyboard, Ctl drag the MKMapView to the orange circle on the bottom bar of ViewController, and select delegate.
This will solve the problem.
As vatrif mentioned in the comments, you must set your delegate BEFORE adding annotations to your MKMapView object.
Others have already explained, odds are high you have not connected your mapview delegate to your controller. Its the first thing to check
i have been working in ios 9 Mapview related app and I experienced the same problem.
somehow I solved my problem, in my case im resizing the mapview.
I added delegate after i resize the mapview. it works now perfectly.!
After having set the delegate for the mapview if still the viewforannotation not getting called then this is something which you have missed - set the self.mapView.showsUserLocation to YES, in interface builder you can tick the shows userLocation option in attributes inspector.