UIPopoverController Width Not Setting - ios

My popovers are sizing incorrectly in iOS 7. The height is working fine, but the width is not getting set at all. The popover has a very skinny width, no matter what I set it to. It still works in iOS 6 but breaks in iOS 7. Is there something new I need to do with popovers in 7 that I'm missing?
Here's the code that works in iOS 6 and not iOS 7:
self.mediaPicker = [[UIImagePickerController alloc] init];
self.mediaPicker.contentSizeForViewInPopover = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
self.cameraPickerPopover = [[UIPopoverController alloc] initWithContentViewController:self.mediaPicker];
self.cameraPickerPopover.popoverContentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
self.cameraPickerPopover.delegate = self;
[self.cameraPickerPopover presentPopoverFromRect:self.toolbar.frame inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:animated];
I found out contentSizeForeViewInPopover is deprecated in iOS 7 so I updated the code as follows and it's still not working:
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
self.mediaPicker.contentSizeForViewInPopover = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
} else {
self.mediaPicker.preferredContentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
}

The answer provided here
How to change the size width of UIImagePickerController on iPad?
is correct, except that for iOS 7, the contentSizeForViewInPopover property should be replaced by the preferredContentSize property.
The UIImagePickerController's delegate implements the UIImagePickerControllerDelegate and the UINavigationControllerDelegate protocols.
Adding the following method in the delegate implementation solves the issue in iOS 7 for me :
- (void)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController animated:(BOOL)animated
{
if (SYSTEM_VERSION_GREATER_THAN(#"7.0"))
viewController.preferredContentSize = CGSizeMake(800,800);
else
viewController.contentSizeForViewInPopover = CGSizeMake(800, 800);
}

Related

UIView issue with iPad Air 2. Touches go through, any ideas why this might be?

So I have a custom UIView class (which I call UIStageView) that emulates the look of a prompt in which the background is darkened and its view brought to center (code below). Now, it works perfectly when run on any iPad EXCEPT iPad airs.
For some reason, touch immediately goes through the UIStageView and into its parent view. Any reason why this might be? I'm running the project on iOS 8.1 and even when I revert back to 7.1 the bug happens. Note that this problem only happens on iPad Airs (physical and emulator). When run on iPads 1-4, it works.
// UIStageView
- (id)initWithFrame:(CGRect)frame withTarget:(UIView *)target {
// Init Background
CGFloat screenWidth = target.frame.size.width;
CGFloat screenHeight = target.frame.size.height;
CGRect rFrame = CGRectMake(0, 10, screenWidth, screenHeight);
if (self = [super initWithFrame:rFrame]) {
[self initSubWithFrame:frame withTarget:(UIView *)target];
[self initExtension];
self.userInteractionEnabled = true;
NSLog(#"StageView inited! :)");
}
return self;
}
- (void)initSubWithFrame:(CGRect)frame withTarget:(UIView *)target {
[self setBackgroundColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:.8]];
_properFrame = frame;
_entranceFrame = CGRectMake(frame.origin.x, frame.origin.y-frame.size.height/2, frame.size.width, frame.size.height);
_babyView = [[UIView alloc] initWithFrame:_entranceFrame];
[_babyView setBackgroundColor:[UIColor whiteColor]];
_babyView.layer.cornerRadius = 15;
_babyView.layer.masksToBounds = YES;
[self addSubview:_babyView];
_target = target;
_indent = 5;
}
Basically, the way my code works is that the UIStageView itself becomes relegated to serving as a background while the _babyView becomes the main view and is what gets interacted with by the user.
I also have a method set up that removes the UIStageView from its parent view when tapped.
This works perfectly on any iPad I've tried (physical and emulator) EXCEPT iPad Airs. Any ideas? :\
Fixed it! As it turns out, declaring #property (nonatomic)float alpha was causing UIView to malfunction. I noticed my UIView wouldn't accept touches at all on either iPad Air or iPad Retina when I didn't explicitly set it (i.e. _alpha = .5) and it would fail only on iPad Air when I did set it (i.e. _alpha = .5).
EDIT:
Just found out that alpha really is a reserved word and I just never noticed. My bad :\

popover full screen in iOS 8

I have the following code for a UIPopoverController. It is working fine in iOS 7. However, in iOS 8, the popover becomes full-screen which I do not want. How do I keep the popover from filling the entire screen in iOS8?
CGRect buttonFrame = [[[[[self tabBarController] tabBar] subviews] objectAtIndex:index+1] frame];
popover = [[UIPopoverController alloc]initWithContentViewController:viewmapmenu] ;
popover.popoverContentSize = CGSizeMake(95, 128.0) ;
popover.delegate = self ;
[popover presentPopoverFromRect:buttonFrame inView:self.tabBarController.tabBar permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES] ;
Try to add this delegate method.
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller;{
return UIModalPresentationNone;
}
See, here is the situation. if you are presenting the popover in iPhone then it will not work in iOS 8 as Apple has completely restricted it even if it was previously working. Now you cannot present popover in iPhone as all the access to the private methods of UIPopover is blocked.
You can look into the FPopover Library in github to use popover in iPhone:-
https://github.com/50pixels/FPPopover

Using UIImagePickerController in iPad Mini iOS 7

I have an app targeting iPhone. The UIImagePickerController works fine on iPhone, but when I open it with iPad Mini on iOS 7, the top part of UIImagePickerController was hidden, which hide the front/back camera toggle button. How can I solve this?
Update:
I observed through subview hierarchies that the "CAMFlipButton" has wrong frame:
<CAMFlipButton: 0x176e6250; baseClass = UIButton; frame = (310.5 9.5; 48 70); opaque = NO; layer = <CALayer: 0x176e63c0>>
I had the same issue; it seems to affect only the iPad Mini (but only the non-retina version), on both iOS 7 and 8. Not sure why not many people faced this issue, but I couldn't find a working solution or workaround.
So what I did (what I hacked!) is I detect when this happens (when the button ends up outside the window bounds), and correct it, by moving the button back into the window, and adding my own image to the button.
#interface MyImagePickerController : UIImagePickerController
#end
#implementation MyImagePickerController
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
showFlipButtonInSubviews(self.view);
}
void showFlipButtonInSubviews(UIView *view) {
if ([[[view class] description] isEqualToString:#"CAMFlipButton"]) {
if (view.x + view.width > UIScreen.mainScreen.bounds.size.width + 5) {
// Fixes this: http://stackoverflow.com/questions/20895993/using-uiimagepickercontroller-in-ipad-mini-ios-7
// Happens on iPad Mini non-retina only
view.x = UIScreen.mainScreen.bounds.size.width - view.width - 10;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 23, 16)];
imageView.image = [UIImage imageNamed:#"switch-camera"];
[view addSubview:imageView];
}
} else {
for (UIView *subview in [view subviews]) {
showFlipButtonInSubviews(subview);
}
}
}
#end
Why UIScreen.mainScreen.bounds.size.width + 5 you ask? Simply because on the iPad Mini retina, that button has 4 pixels outside the window, but it still shows correctly, so I don't want to apply this hack then.
My switch-camera image looks like this:
(hard to see, it's white! right-click or drag it around to see it...)

Phonegap-Plugin ExternalFileUtil doesn't work on all devices

I'm using the ExternalFileUtil-Plugin from Phonegap (https://github.com/phonegap/phonegap-plugins/tree/master/iOS/ExternalFileUtil). But it work's only at iPhone. It work's on iPhone-simulator with iOS 6.0 and 6.1 and work's on iPhone 4 and 5 with iOS 6.x. But it doesn't work on iPad, neither on simulator nore on devices and on iPod Touch with iOS 5.1 it doesn't work too ;(
I've tried any suggestions described in the comments on http://www.tricedesigns.com/2012/08/15/open-with-in-ios-phonegap-apps/ but nothing helps me.
In my opinion the following lines must be adjusted:
UIDocumentInteractionController *controller = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
controller.delegate = self;
controller.UTI = uti;
[controller retain];
CDVViewController* cont = (CDVViewController*)[ super viewController ];
CGRect rect = CGRectMake(0, 0, cont.view.bounds.size.width, cont.view.bounds.size.height);
[controller presentOptionsMenuFromRect:rect inView:cont.view animated:YES];
Have somebody any suggestions?
My current solution for this issue: Replace
CGRect rect = CGRectMake(0, 0, cont.view.bounds.size.width, cont.view.bounds.size.height);
with this
CGRect rect = CGRectMake(0, 0, 1500.0f, 50.0f);
and it works like a charm. Thanks to Mahendra Liya (see comment on tricedesigns.com).

iPad custom size of modal view controller

I have a couple of modal view controllers of certain size. I'm trying to avoid the use of custom views (creating full screen black translucent overlay over current view, add the modal view over that view, do the animations, etc) to present it because there is no modalPresentationStyle that fits the size of my controllers.
Now I'm using UIModalPresentationPageSheet but my view is smaller in height and I have an ugly blank space
Desired presentation
_______________
| _______ |
| | | |
| | MyVC | |
| | | |
| ------- |
---------------
Actual presentation
_______________
| | | |
| | MyVC | |
| | | |
| |-------| |
| | blank | |
---------------
If I use the UIModalPresentationFormSheet the container is smaller in width.
I'm trying to figure out how to do it but I don't know if it's possible. What is the solution to the problem of presenting a modal VC smaller than any of the presentationStyles? The only solution is to arrange a "custom modal view controller engine"? Popovers doesn't fit my design requirements :(
As some other users here, I also had the problem that the origin of the modal view controller was not correct. After some experiments, I found a solution that worked for me:
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, <width>, <height>);
}
I obtained the following result (link text) by using:
self.modalPresentationStyle = UIModalPresentationFormSheet;
and by presenting it as a modal view controller. Let me know if you need further help.
All these answers will not work on ios8 SDK.
This will work:
AboutViewController * _aboutViewController = [[AboutViewController alloc] init];
_aboutViewController.modalPresentationStyle = UIModalPresentationFormSheet;
if(IS_IOS8)
{
_aboutViewController.preferredContentSize = CGSizeMake(300, 300);
}
[self presentViewController:_aboutViewController animated:YES completion:nil];
In AboutViewController.m
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
if(!IS_IOS8)
{
self.view.superview.bounds = CGRectMake(0, 0, 300, 300);
}
}
IS_IOS8
#define IS_IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8)
In iOS 8 you can also use UIPresentationController which gives you more customization options.
I had an issue getting the custom sized modal to center until I figured out what ViewController.view.superview.frame was set to initially. It is determined based on the UIModalPresentation type. superview.center isn't even needed(as far as my testing shows).
Also, I set the coordinates dynamically using [UIScreen mainScreen].applicationFrame, only supporting landscape orientation for now. You have to do a conditional check to support both portrait and landscape by flipping the X/Y and Height/Width values.
Here was my first working solution for iOS 6.0:
ViewController.modalPresentationStyle = UIModalPresentationFormSheet;
ViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:ViewController animated:YES completion:nil];
ViewController.view.superview.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
ViewController.view.superview.frame = CGRectMake(
// Calcuation based on landscape orientation (width=height)
([UIScreen mainScreen].applicationFrame.size.height/2)-(320/2),// X
([UIScreen mainScreen].applicationFrame.size.width/2)-(320/2),// Y
320,// Width
320// Height
);
And then I looked at the previous answer and face palmed. Shortens my solution a tad by replacing the last line with:
ViewController.view.superview.bounds = CGRectMake(0, 0, 320, 320);
EDIT for final solution and remarks.
The best way to do this is to change the bounds property on the superview of the view being presented inside the formsheet. When you present a view modally, the presented view is embedded inside another view.
You should set the bounds property of the superview to the same rect as the view's bounds. First add a private ivar in your class:
#implementation MySpecialFormsheet {
CGRect _realBounds;
}
It's best to do this in viewWillAppear:. Add the following code to the view controller that is being presented modally:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.view.superview.bounds = _realBounds;
}
You need to cache _realBounds in your viewDidLoad method:
- (void)viewDidLoad {
_realBounds = self.view.bounds;
[super viewDidLoad];
}
even for reducing the forma sheet height and width you can use
[self.view.superview setBounds:CGRectMake(0, 0, 450, 480)];
This is my solution for a NOT autolayout view (never tried with autolayout) and compliant with iOS 7 and iOS 8.
At first be sure to call the modal view in this way:
CloudSettingsViewController *cloudController = [[CloudSettingsViewController alloc] initWithNibName:#"CloudSettingsView" bundle:nil];
CGRect originalBounds = cloudController.view.bounds;
cloudController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
cloudController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:cloudController animated:YES completion:nil];
With iOS 8 set the preferredContentSize in the viewDidLoad method of the modal view.
- (void)viewDidLoad {
[super viewDidLoad];
// backup of the original size (selected in interface builder)
height = self.view.frame.size.height;
width = self.view.frame.size.width;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8) // versioni successive ios 8
self.preferredContentSize = CGSizeMake(width, height); // this is necessary to get the correct size of the modal view
}
This works ALSO when the modal view needs to display the keyboard on iPad.
With previous versions of iOS 8 you should set the bounds after presentViewController call:
[currentController presentViewController:controlPanelController animated:YES completion:nil];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8)
cloudController.view.superview.bounds = originalBounds;//it's important to do this after
The approaches described above need to be tweaked for iOS7:
// set desired bounds, then call -presentFromViewController:
#implementation PresentedViewController
{
CGRect _presentationBounds;
}
- (void)presentFromViewController:(UIViewController *)viewController
{
self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
self.modalPresentationStyle = UIModalPresentationFormSheet;
_presentationBounds = self.view.bounds;
[viewController presentViewController:self animated:YES completion:nil];
}
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
if (!CGRectIsEmpty(_presentationBounds))
{
self.view.superview.bounds = _presentationBounds;
_presentationBounds = CGRectZero;
}
}
(This code also works on iOS6.)
Even I was struggling with the same issue for quite a while. After giving few tries from many of the answers given here I came up with a solution that worked for me pretty well.
Here is the code while presenting the view controller.
SomeViewController *sovcObj = [[SomeViewController alloc] initWithNibName:#"SyncOptionsViewController" bundle:nil];
someObj.modalPresentationStyle = UIModalPresentationFormSheet;
someObj.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:someObj animated:YES completion:nil];
someObj.view.superview.bounds = CGRectMake(0, 0, 400, 400); // whatever width and height you want
In the xib (if you are using one) in the 'Simulated Metrics' section select 'Freeform' size.
Apart from this you need to write the below code in your presented view controller (i.e.., SomeViewController in this example)
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.view.superview.bounds = CGRectMake(0, 0, 400, 400); // whatever width and height you want
}
This code also works for iOS 7 as well
One solution is to use UIModalPresentationPageSheet to present a page sheet and then immediately resize the modal view. This is fully explained in this answer to another question.
Resize the modal view "after" it is presented using presentModalViewController method.See this link to resize modal View https://coderwall.com/p/vebqaq
You can use MZFormSheetController like this:
MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithSize:customSize viewController:presentedViewController];
[presentingViewController mz_presentFormSheetController:formSheet animated:YES completionHandler:nil];
This solution worked for me as I had the same issue.
My modal view structure is the following (I use UIModalPresentationCurrentContext at both presenting and presented controllers to achieve transparency in the presented VC)
ModalViewController
> UIView (view) - resized to the same size as the presenting controller but has semi-translucent background - done automatically
>> UIView (contentView) - the true view with the content of the popup - this is the one that got consistently placed at the top of the screen all the time
In ModalViewController I overwrote the following method to fix the positioning issue:
- (void) viewWillLayoutSubviews(){
[super viewWillLayoutSubviews];
CGRect r = self.view.bounds();
self.contentView.center = CGPointMake(r.size.width/2,r.size.height/2);
}
I actually create and size the content view first but in different method.
Hope this helps someone.

Resources