How to attach a UIPopover to a rectangle I have drawn - ios

I have an iPad app (XCode 4.6, ios 6.2, ARC and Storyboards). I have drawn a GCRect on a position of a UIView.
CGRect rectangle = CGRectMake( [appSelected.aPosX floatValue], [appSelected.aPosY floatValue],[appSelected.aPosW floatValue], [appSelected.aPosH floatValue]);
I have a method that does the drawing for me; this is the code for that method:
-(void)showHTMLHelp:(NSString *)htmlString pointTo:(id)target background:(UIColor *)bgColor {
UIViewController* popoverContent = [[UIViewController alloc] init];
UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 300)];
popoverView.backgroundColor = [UIColor colorWithWhite:(CGFloat)1.0 alpha:(CGFloat)1.0]; // frame color?
popoverContent.view = popoverView;
//resize the popover view shown in the current view to the view's size
popoverContent.contentSizeForViewInPopover = CGSizeMake(200, 300);
// add the UIWebView for RichText
UIWebView *webView = [[UIWebView alloc] initWithFrame:popoverView.frame];
webView.backgroundColor = [UIColor whiteColor]; // change background color here
// add the webView to the popover
[webView loadHTMLString:htmlString baseURL:[NSURL URLWithString:nil]];
[popoverView addSubview:webView];
//create a popover controller
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
//present the popover view non-modal with a refrence to the button pressed within the current view
if([target isKindOfClass: [UITextField class]])
[popoverController presentPopoverFromRect:((UITextField *)target).frame inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
else if([target isKindOfClass: [UISegmentedControl class]])
[popoverController presentPopoverFromRect:((UISegmentedControl *)target).frame inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
else if([target isKindOfClass: [UIButton class]])
[popoverController presentPopoverFromRect:((UIButton *)target).frame inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
else
[popoverController presentPopoverFromRect:*(CGRect *)CFBridgingRetain(target)
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
Now I want to have a UIPopover point to that rectangle. Since GCRect is a C structure, I can't figure out how to do it. This is what I tried, but obviously it's wrong. How can I do this? This is the code where I call the method to display the popover:
PreferencesViewController *pvc = [[PreferencesViewController alloc] init];
[pvc showHTMLHelp:html pointTo: rectangle background:[UIColor whiteColor]];

There is absolutely no problem with passing a C structure (or C primitive variable) to an Objective-C method. In fact, presentPopoverFromRect:inView:permittedArrowDirections:animated: takes a simple CGRect as you can tell by the header (or the documentation):
- (void)presentPopoverFromRect:(CGRect)rect
inView:(UIView *)view
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
animated:(BOOL)animated;
Simply call it like this:
[popoverController presentPopoverFromRect:rectangle
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
And as Mar0ux already pointed out, it's CGRect, not GCRect. CG stands for Core Graphics.

May i ask you why you are sending an CGRect and casting it to 'id'? Where is the sense?! I would prefer to change your parameter type to CGRect too.
Kind regards.

Related

How to display a UIPopover from another class?

I have a iPad app (XCode 5, iOS 6, ARC and Storyboards), which has a class to display a UIView. From a separate class, I want to display a UIPopover under a certain condition.
I'm having a problem with the last line of code:
// create a popover for login or registration
UIViewController* popoverContent = [[UIViewController alloc]init];
UIView* popoverView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 280, 180)];
popoverView.backgroundColor = [UIColor lightGrayColor];
popoverContent.view = popoverView;
//resize the popover view shown in the current view to the view's size
popoverContent.contentSizeForViewInPopover = CGSizeMake(320, 280); // was 180
//create a popover controller
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
// if previous popoverController is still visible... dismiss it
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
}
// [popoverController presentPopoverFromRect:popoverView inView:self
// permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
SettingsViewController *svc = [[SettingsViewController alloc]init];
[popoverController presentPopoverFromRect: popoverView inView:svc.view.frame
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
It's telling me:
Sending 'UIView *__strong' to parameter of incompatible type 'CGRect' (aka 'struct CGRect')
How do I fix this? (I've tried different ways of presenting the popover, but none of them work).
Assuming the popoverView is the section of the svc view you want the popover to present from, your code should read:
[popoverController presentPopoverFromRect:popoverView.frame inView:svc.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
This will correct that error.
Edit: The reason it's probably not displaying for you is because you seem to be misunderstanding the presentPopoverFromRect method. The frame you indicate in the presentPopoverFromRect method needs to correspond the point of the view you'd like the popover to emerge from. For example, to have the popover present from the top left corner of the view, do something like this:
[popoverController presentPopoverFromRect:CGRectMake(0, 0, 1, 1) inView:svc.view
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

Can't change size for UIPopover?

I'm writing an app that needs to spawn a popover in order to add a new note. To that end, I have something that does kind of the trick, however, I can't seem to adjust the size of the popover. This is how I'm spawning it:
UIButton* btn =sender;
UIViewController* fooTroller = [[UIViewController alloc] init];
CGRect rectFoo = CGRectMake(0, 0, 100, 100);
UIView* fooView = [[UIView alloc] initWithFrame:rectFoo];
[fooView setBackgroundColor:[UIColor redColor]];
[fooTroller setView:fooView];
popOver =[[UIPopoverController alloc] initWithContentViewController:fooTroller];
[popOver presentPopoverFromRect:btn.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionLeft
animated:YES];
Any thoughts? It's not respecting the view size.
You should not be calling setView: on the view controller. Let the view controller setup its own view.
The proper way to size a popover is to either override the contentSizeForViewInPopover method of your view controller to return the size or to set the popoverContentSize property on the popover.
UIButton* btn =sender;
UIViewController* fooTroller = [[UIViewController alloc] init];
popOver = [[UIPopoverController alloc] initWithContentViewController:fooTroller];
popOver.popoverContentSize = CGSizeMake(100, 100);
[popOver presentPopoverFromRect:btn.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionLeft
animated:YES];

How to display a popover programmatically from a uibutton that is also created programmatically (Not using interface builder)

I have a button I have created programmatically within a view controller. Once the button is pressed I want it to to use a method to create the popover programmatically.
The button which is created in the ViewDidLoad in my view controller.m
UIView *moreFundInfoView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 540, 620)];
[self.view addSubview:moreFundInfoView];
[moreFundInfoView setBackgroundColor:[UIColor RMBColor:#"b"]];
btnContact = [UIButton buttonWithType:(UIButtonTypeRoundedRect)];
[btnContact setFrame:CGRectMake(390, 575, contactButton.width, contactButton.height)];
btnContact.hidden = NO;
[btnContact setTitle:#"Contact" forState:(UIControlStateNormal)];
[moreFundInfoView addSubview:btnContact];
[btnContact addTarget:self action:#selector(showContactDetails:) forControlEvents:UIControlEventTouchUpInside];
Then I have the method I use when the button is pressed.
-(void) showContactDetails: (id) sender
{
UIViewController *popoverContent = [[UIViewController alloc]init];
UIView *popoverView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 200, 300)];
[popoverView setBackgroundColor:[UIColor RMBColor:#"b"]];
popoverContent.view = popoverView;
popoverContent.contentSizeForViewInPopover = CGSizeMake(200, 300);
UIPopoverController *contactPopover =[[UIPopoverController alloc] initWithContentViewController:popoverContent];
[contactPopover presentPopoverFromRect:btnContact.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES ];
[contactPopover setDelegate:self];
}
What am I missing here? Cause it runs fine, but as soon as I click the button the app crashes. I think it is a delegate issue, but I am not sure. Any advice would be appreciated.
I think this code will help you. You are certainly missing delegate methods
ViewController *viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:navigationController];
popover.delegate = self;
popover.popoverContentSize = CGSizeMake(644, 425); //your custom size.
[popover presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections: UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionUp animated:YES];
Just make sure you are not forgetting UIPopover Delegate methods or else application will definitely crash. It is mandatory.
UIViewController *controller = [[UIViewController alloc] init];
[view removeFromSuperview]; //view is a view which is displayed in a popover
controller.view = view;
UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:controller];
popover.delegate = self;
[popover presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
All I had to do was change the property from "retain" to "strong" in the .h file and it works, stopped the app from crashing.
Yes, changing property for "retain" to "strong" makes you to hold your picker view object.
I think the problem with your code was, UIPopoverController object gets deallocated automatically when method finishes.
making strong property gets you to strongly point an object.

UIPopoverController - SIGABRT when Presented

I'm attempting to present a popoverView when a barButton is pressed. Unfortunately, the app crashes with the signal SIGABRT every time I try to call it. The "Empty.xib" does have a view designed in it. (As I'm using a barButton, I was unable to use the frame, if you have a workaround for that, please say so too).
- (IBAction)loadPopover:(id)sender
{
UIView *someView = [[UIView alloc] init];
UIViewController *someVC = [[UIViewController alloc] initWithNibName:#"Empty.xib" bundle:[NSBundle mainBundle]];
UIPopoverController *popoverController = [[UIPopoverController alloc] initWithContentViewController:someVC];
someView.frame = CGRectMake(0, 44, 320, 372);
someView.backgroundColor = [UIColor lightGrayColor];
popoverController.delegate = self;
self.popoverView = popoverController;
[self.popoverView presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
// CGRect popoverRect = [self.view convertRect:[btn frame] fromView:[btn superview]];
CGRect popoverRect = CGRectMake(0, 88, 320, 311);
popoverRect.size.width = MIN(popoverRect.size.width, 100);
[self.popoverView presentPopoverFromRect:popoverRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
Remove .xib part from initWithNibName:#"Empty.xib". Change line to this:
UIViewController *someVC = [[UIViewController alloc] initWithNibName:#"Empty" bundle:nil];
Edit:
From here -
The nib file name should not contain any leading path information.
Few suggestions here.
Check if the view's outlet is connected
Why do you need to allocate a UIView like the following? UIView *someView = [[UIView alloc] init];
Check if the sender is of type of UIBarButtonItem
What is the retain policy for self.popoverView? Check if it is retain or strong (if ARC)
Why do you present the popover two times?
Said this, here a simple snippet.
UIBarButtonItem* barButton = (UIBarButtonItem*)sender;
UIViewController *someVC = [[UIViewController alloc] initWithNibName:#"Empty" bundle:[NSBundle mainBundle]];
UIPopoverController *popoverController = [[UIPopoverController alloc] initWithContentViewController:someVC];
popoverController.delegate = self;
self.popoverView = popoverController;
[self.popoverView setPopoverContentSize:CGSizeMake(300, 200)];
[self.popoverView presentPopoverFromBarButtonItem:barButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
P.S. Make attention to memory if you don't use ARC.
Hope it helps.

Releasing a popover which takes great amount of memory

I am using a popover view to present a large amount of flags of which the your can select.
There is something wrong with my code since soon after I open this popover memory is not released (the viewcontroller "flagsViewController" is ok and clean, it does init and release each and every item inside of it.
What am I doing wrong? How can I free memory as soon as the popover is closed?
-(void)presentFlags
{
[self.popoverController dismissPopoverAnimated:YES];
FlagsViewController *controller = [[FlagsViewController alloc]
initWithNibName:#"FlagsViewController"
bundle:[NSBundle mainBundle]] ;
UINavigationController *container = [[UINavigationController alloc] initWithRootViewController:controller];
UISegmentedControl *ctrl = [[UISegmentedControl alloc] initWithItems:segmentedItems];
ctrl.frame = CGRectMake(0, 6, 500, 30);
[ctrl addTarget:self action:#selector(changeSeg:) forControlEvents:UIControlEventValueChanged];
ctrl.segmentedControlStyle = UISegmentedControlStyleBar;
//ctrl.momentary = YES;
ctrl.tintColor = [UIColor darkGrayColor];
UIImage *theImage = [UIImage imageNamed:#"highlight_country.png"];
[ctrl setImage:theImage forSegmentAtIndex:0];
[container.navigationBar addSubview:ctrl];
[ctrl release];
//
//create a popover controller
self.popoverController = [[[UIPopoverController alloc]
initWithContentViewController:container] autorelease];
[container release];
[popoverController setPopoverContentSize:CGSizeMake(500, 600)];
//present the popover view non-modal with a
//refrence to the button pressed within the current view
[popoverController presentPopoverFromRect:CGRectMake(popoverArrowPossition, 0.0, 0.0, 52.0) inView:super.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
[controller release];
}
Working with the UIPopoverController has been pretty difficult but I solved this problem by doing the following setting the Delegate of the Popover Controller to self (popoverController.delegate = self) and adding the UIPopoverControllerDelegate Protocol to your Class Header
Next, I implemented the - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController delegate method and here I released the popoverController and set it to nil.
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
[self.popoverController release];
self.popoverController = nil;
}
Please note: This delegate method won't be called if you dismiss the popover via code (i.e. using dismissPopoverAnimated), it'll only be called if this User dismisses it by tapping outside the popover etc.

Resources