UIPopoverController inRect issue - iphone

I have a UIViewController that contains a UIView subclass as a subview. In the subview, I dynamically create another UIView. When the innermost view is created then the UIViewController is informed via a delegation that it must show a UIPopovercontroller whose arrow head need to be pointing to the inner most view. In the delegate method call, I also pass the origin of the inner most view so that the UIViewcontroller make use of this CGPoint to create the popover controller. The problem is that the UIPopovercontroller is not being positioned at the desired location.
MyController* myController = [ [ MyController alloc] init];
UINavigationController *aNavController = [[UINavigationController alloc] initWithRootViewController: myController];
self.popOver = [[[UIPopoverController alloc]
initWithContentViewController:aNavController] autorelease];
[aNavController release];
CGRect rect;
//CGPoint p = CGPointMake(currentPage.frame.size.width/2, currentPage.frame.size.height/2);
rect.origin = point; //here point is the origin of the inner most view
rect.size = self.view.frame.size;
[self.popOver presentPopoverFromRect: rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
What I am missing in this code that is forcing the popover to appear deviated from the position instead of at the desired place.
Thanks

I think your are not passing the correct view to your popOver, check once ...
[self.popOver presentPopoverFromRect: rect inView:myInnerView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

The rect you are presenting your popover from may be too large.
You have it set to the size of the entire view instead of the size of your inner most view.

Related

Setting size of viewController's view in UIView

UIView *view =[[UIView alloc] initWithFrame:CGRect(0,0,300,70)]; //--(View created)
someViewController *someViewControllerObject = [..]; //View Controller Object created.
[view addSubview:[someViewControllerObject.view]];
I want to fit the view controller's view in the UIView's object. The above code doesn't work correctly. Can you help me figure this out?
The simplest would be to just set the frame of the controller view to the bounds of the outer view;
UIView *view =[[UIView alloc] initWithFrame:CGRect(0,0,300,70)]; //--(View created)
someViewController *someViewControllerObject = [..]; //View Controller Object created.
someViewController.view.frame = view.bounds;
[view addSubview:[someViewControllerObject.view]];
#david's answer is correct to set the initial frame of the view controller's view. set the autoResizingMask to get the behavior you want when the superview changes.
someViewControllerObject.view.frame = view.bounds;
someViewControllerObject.view.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
[view addSubview:someViewControllerObject.view];
This code will make it the same size as your current view.
someViewControllerObject.view.frame = view.bounds;
[view addSubview:[someViewControllerObject.view]];

Set UIPopOverController size

I have a view with a bunch of button in a UIScrollView. When the user presses a button, I want a UIPopOverController to display pointing at the selected button. It kind of works, but the popover is the wrong size and points to a random point in the view. Here is my code.
-(void)detail:(id)sender{
UIButton *button = sender;
NSLog(#"tag = %i", button.tag);
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self.popover = [[UIPopoverController alloc] initWithContentViewController:navController];
self.popover.delegate = self;
[self.popover presentPopoverFromRect:button.bounds inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
Than the problem with the size of the popover:
In the view that is inside the popover, I have:
self.contentSizeForViewInPopover = scroll.contentSize;
NSLog(#"%f, %f", scroll.contentSize.height, scroll.contentSize.width);
NSLog(#"showing: %f, %f", self.contentSizeForViewInPopover.height, self.contentSizeForViewInPopover.width);
and both logs are matching. So I think everything should work correctly. But it doesn't. Here is a screen shot. Let me know if you need more of my code. Thanks in advance.
First thing I noticed is that you should be using the button.frame not the button.bounds for the from rectangle. The difference between these UIView properties:
The geometry of a view is defined by its frame, bounds, and center
properties. The frame property defines the origin and dimensions of
the view in the coordinate system of its superview and is commonly
used during layout to adjust the size or position of the view.
The bounds property defines the internal dimensions of the view as it
sees them and is used almost exclusively in custom drawing code.
You can set the height of your popover controller using its setPopoverContentSize message:
// so something like this ...
[self.popover setPopoverContentSize:CGSizeMake(320, 460)];
// and to bind the popover to your button
[self.popover presentPopoverFromRect:button.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
Regarding the size of the popover only: I managed to do it with a variable heighted UILabel:
UILabel *hinweis;
hinweis.text = #"...";
hinweis.frame = CGRectMake(x,y,width,800);
[hinweis sizeToFit];
And for the arrow: have you tried a different inView param like self.parentViewController.view?

UIPopoverController forces iPad into Portrait orientation

I think the issue here is that I'm trying to call a mediaPicker and that doesn't support other orientations...
Does anyone have a fix for this?
Here is my current code:
- (IBAction)openMediaPicker:(id)sender {
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAnyAudio];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES; // this is the default
mediaPicker.modalPresentationStyle = UIModalPresentationPageSheet;
//mediaPicker.prompt = #"Select items to play";
[self presentModalViewController:mediaPicker animated:YES];
[mediaPicker release];
// Init a Navigation Controller, using the MediaPicker as its root view controller
UINavigationController *theNavController = [[UINavigationController alloc] initWithRootViewController:mediaPicker];
[theNavController setNavigationBarHidden:YES];
// Init the Popover Controller, using the navigation controller as its root view controller
popoverController = [[UIPopoverController alloc] initWithContentViewController:theNavController];
// Make a rect at the size and location of the button I use to invoke the popover
CGRect popOverRect = chooseMusicButton.frame;
// Specify the size of the popover
CGSize MySize = CGSizeMake(520.0, 720.0);
[popoverController setPopoverContentSize:MySize animated:YES];
// Display the popover
[popoverController presentPopoverFromRect:popOverRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
popoverController.delegate = self;
}
This code is overly complicated. First you present the media picker modally, then you present it as a popover; why? In the popover, you stuff it into a navigation controller before presenting it; why? Presenting a media picker on iPad is much simpler than that:
MPMediaPickerController* picker =
[[[MPMediaPickerController alloc] init] autorelease];
picker.delegate = self;
UIPopoverController* pop =
[[UIPopoverController alloc] initWithContentViewController:picker];
self.currentPop = pop;
[pop presentPopoverFromRect:[sender bounds] inView:sender
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[pop release];
That works in any orientation and even survives rotation while the popover is showing.
All pre-defined modal controllers support all orientations but they must be presented from the root view controller for them to behave correctly in orientation and rotation. My guess is that that the "self" in your code is not the root view controller. You may have to re-architect the code a bit to make this happen if possible.
There are other hacks I have seen to make it work without being presented from the root view controller but they all seemed to be asking for trouble such as extending UIViewController with a category to over-ride interfaceOrientation.
If you can present it from the root view controller, it would be the simplest and cleanest but I realize it is not always possible (e.g., it is inside a library you are providing to third party apps to embed).

iPhone: Weird space at the top of UINavigationController

I'm having a strange problem with adding a UINavigationController to my iPhone application. I add the controller as follows:
myViewController *viewController = [[myViewController alloc] initWithNibName:#"myView" bundle:nil];
myNavigationViewController *navigationController = [[myNavigationViewController alloc] initWithRootViewController:viewController];
UIView *finalView = myeNavigationViewController.view;
[self.view addSubview:finalView];
All seems to work as planned except I get a weird white space at the top of my view between the status bar and the UINavigationController title bar.
alt text http://www.andrewskinner.name/problem.png
I've searched online but don't really know what to search for. Has anyone else had this problem? Can you point me in the direction of some help?
Thanks in advance.
What does the line
UIView *finalView = myeNavigationViewController.view;
add to the code? It's redundant as you can add the view directly without assigning it to a UIView first - plus it's incorrect as it references the myNavigationController and not navigationController..
I tend to do this
myViewController *viewController = [[myViewController alloc] initWithNibName:#"myView" bundle:nil];
myNavigationViewController *navigationController = [[myNavigationViewController alloc] initWithRootViewController:viewController];
[navigationController.view setFrame: [self.view bounds]];
navigationController.delegate = self;
[self.view addSubview:[navigationController view]];
Setting the frame to the bounds also removes the white space at the top you were asking about.
Check out the answers in this question:
Not sure why UIView is being nudged up by around 10px
The issue is that UINavigationController ideally should be the direct subView of UIWindow. It will position and size right by itself. When you add UINavigationController into another custom view of a UIWindow subview, you need to take care of the position and size of this custom view by taking into account whether the status bar is shown or not in the UIWindow.
My suggestion is to make the custom view as a subclass of UINavigationController:
mySubClass_NavigationController*nav=[[mySubClass_NavigationController alloc] initWithRootViewController:viewController ];
[myUIWindow addSubview:nav.view];
and inside the mySubClass_NavigationController, you can do all the customization that you are doing now in your self (whatever that controller is).
I struggled with this for a while too using very similar code to the op's and also had a white bar above my navigation controller.
My problem occurred when adding the UINavigationController as a view in a UITabController. The space in my case was caused by the UINavigationBar part of the UINavigationController taking into account the status bar and it was actually overlapping part of the view that I was trying to show in the UINavigationController.
This is the code I ended up with in loadView in one of my UITabBarController view controllers.
SomeUITableViewController *screenList = [[SomeUITableViewController alloc] init];
UINavigationController *navController = [[UINavigationController alloc]
initWithRootViewController:screenList];
CGRect frame = [[navController navigationBar] frame];
frame.origin.y = 0; // Was 20, set to 0 to not take into account the status bar.
[[navController navigationBar] setFrame:frame];
[self setView:[navController view]];
There's some more information at http://discussions.apple.com/message.jspa?messageID=7890362.
There is an obscure property in IB called "Hides Bottom Bar on Push". Just check it. It solved the problem for me.
Maybe you have somehow gotten yourself two UIViews,
each with a status bar. Check the xib.

Gap on Navigation Controller

I've got a button on a view. When I click on it, it should load another view, one with a novigation controller. So far I've got this, the button calls this method:
-(IBAction)loadOptionsView:(id)sender {
if (self.optionsRootController == nil) {
//optionsRootController is declared as: UINavigationController *optionsRootController;
optionsRootController = [[UINavigationController alloc] init];
//Options is a UIViewController
Options *myOptions = [[Options alloc] initWithNibName:#"OptionsMenu" bundle:nil];
[optionsRootController pushViewController:myOptions animated:NO];
[myOptions release];
}
[self.view addSubview:optionsRootController.view];
}
What happens when I click the button is that it loads the xib file OptionsMenu on top of the current screen, but there's a gap at the top of the size of the status bar, so I can see the view below. Any help? What's the right method to load a new view that contains a navigation controller?
Thank you all!
I solved this issue by placing after:
[optionsRootController pushViewController:myOptions animated:NO];
this line:
[optionsRootController.view setFrame: [self.view bounds]];
Nice and easy!
I think UINavigationController's designated initializer is
- (id) initWithRootController:(UIViewController *)rootController
So your code above would be better expressed as
//optionsRootController is declared as: UINavigationController *optionsRootController;
//Options is a UIViewController
Options *myOptions = [[Options alloc] initWithNibName:#"OptionsMenu" bundle:nil];
optionsRootController = [[UINavigationController alloc] initWithRootController: myOptions];
[myOptions release];
Is the VIew in your nib the right size for the whole screen? Try turning off the simulated status bar in IB.