I've got a popover segue in my iPad storyboard. The popover contains a Nav Controller which contains my View Controller. I set the preferredContentSize in my View Controller and tried setting the Nav Controller's preferredContentSize from within my View Controller. The popover still fills up the screen though. I even tried the deprecated self.contentSizeForViewInPopover and that didn't work either. I tried in -awakeFromNib and -viewDidLoad.
What am I doing wrong?
- (void) awakeFromNib {
[super awakeFromNib];
self.preferredContentSize = CGSizeMake(500.0, 600.0);
self.navigationController.preferredContentSize = self.preferredContentSize;
self.contentSizeForViewInPopover = self.preferredContentSize;
self.navigationController.contentSizeForViewInPopover = self.preferredContentSize;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.preferredContentSize = CGSizeMake(500.0, 600.0);
self.navigationController.preferredContentSize = self.preferredContentSize;
self.contentSizeForViewInPopover = self.preferredContentSize;
self.navigationController.contentSizeForViewInPopover = self.preferredContentSize;
}
In iOS7 i just use a "fake" preferedContentSize to force a refresh of the popoverSize like that:
CGSize currentSetSizeForPopover = CGSizeMake(400, 130);
CGSize fakeMomentarySize = CGSizeMake(currentSetSizeForPopover.width - 1.0f, currentSetSizeForPopover.height - 1.0f);
self.preferredContentSize = fakeMomentarySize;
self.preferredContentSize = currentSetSizeForPopover;
But in iOS8 it seems not working any more..
It work when i present it, but if i navigate to another viewController and then back to the root the preferredContentSize is not respected anymore..
Related
In my UIViewController class, I'm creating a UIView called safeAreaView and adding it as a subview to the UIViewControllers view property. I'm making it so safeAreaView takes up the entire safe area of the UIViewControllers view property:
- (void) viewDidLoad
{
[self setToolbarWithColor: self.mainToolbarColor animated:NO];
self.tapGestureRecognizer.delegate = self;
self.view.clipsToBounds = YES;
self.view.backgroundColor = [UIColor lightGrayColor];
self.safeAreaView = [[UIView alloc] initWithFrame: CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
self.safeAreaView.clipsToBounds = YES;
self.safeAreaView.delegate = self;
self.safeAreaView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview: self.safeAreaView];
[self.safeAreaView.leadingAnchor constraintEqualToAnchor: self.view.safeAreaLayoutGuide.leadingAnchor].active = YES;
[self.safeAreaView.trailingAnchor constraintEqualToAnchor: self.view.safeAreaLayoutGuide.trailingAnchor].active = YES;
[self.safeAreaView.topAnchor constraintEqualToAnchor: self.view.safeAreaLayoutGuide.topAnchor].active = YES;
[self.safeAreaView.bottomAnchor constraintEqualToAnchor: self.view.safeAreaLayoutGuide.bottomAnchor].active = YES;
[self.safeAreaView loadSubviews];
}
This works fine, but my problem is, at some point after this during the UIViewControllers initialization cycle, safeAreaView updates to account for the statusbar (it's y position moves up 20 and it decreases in size by 20).
I need to layout some subviews on safeAreaView and I don't know the proper time? If I attach the subviews like above, they have the wrong height. And I can't use some auto layout features on the subviews because there are specific things that I need to do. I've also tried executing the above code in viewWillAppear with no luck.
Wondering if anyone had any suggestions?
You can override - (void)layoutSubviews on your safeAreaView class:
- (void)layoutSubviews {
[super layoutSubviews];
// Manual frame adjustment for non-autolayout participating subviews
// ...
}
Another option would be to override your safeAreaView's class frame setter, so each time the frame of your view changes, you'll get a chance to manually set any subview frames as needed.
I am doing a PhoneGap iPad application. In this I had added a HybridPage (which contains webView) as a child view controller and then after that screen I am adding a New Controller (also removed the hybridPage from ParentViewController) which contains Native Controller and again same instance of HybridPage Controller (added two controllers as childs).
Here My Native Controller size is (320,704) and Hybrid Controller size is (702,704).
Now the problem is I am not able to interact with Half frame of Hybrid controller from right side (320 width from the end of contentoffset of the view).
I have given the two viewControllers frames even though I am not able to interact with some rect of Hybrid controller.
(void)setDashboardRootViewController:(UIViewController*)rootViewController
{
if ([[self childViewControllers] containsObject:[MCIPadRootViewController getIPadRootViewController].mcWebViewController])
{
[[MCIPadRootViewController getIPadRootViewController] removeMCWebViewController];
}
[self addChildViewController:self.dashboardViewController];
[self.dashboardContainerView addSubview:self.dashboardViewController.view];
if ([rootViewController isKindOfClass:[MCLoginFlowWebViewController class]])
{
[self addChildViewController:[MCIPadRootViewController getIPadRootViewController].mcWebViewController];
[MCIPadRootViewController getIPadRootViewController].mcWebViewController.view.frame = CGRectMake(0, 0, self.mcWebViewContainerView.frame.size.width, self.mcWebViewContainerView.frame.size.height);
[self.mcWebViewContainerView addSubview:[MCIPadRootViewController getIPadRootViewController].mcWebViewController.view];
}
}
Where can i set Child ViewController's Frame. Here i had set the viewcontroller's view frame but it is not effecting.
Could anybody help me to get out from this issue.
Please find the Screen shot for clarity.
You would typically set the frame of a child view controller's view in 2 places.
Right before you add it to the parent. Search for a call to addChildViewController: in the parent view controller. Set frame right before that call (there may be 2 calls to addChildViewController:).
If the size changes due to rotation you'll need to reset the frame of the child view controller's view in the parent view controller's viewWillLayoutSubviews: method.
Here's an example from a custom split view controller.
Notice the 2 places where where #1 is set.
- (void)setMasterViewController:(UIViewController *)controller
{
if (!_masterViewController) {
// Add the new controller
controller.view.frame = self.masterView.bounds;
[self addChildViewController:controller];
[self.masterView addSubview:controller.view];
[controller didMoveToParentViewController:self];
_masterViewController = controller;
}
else if (_masterViewController != controller) {
// Transition from the old to new controller
controller.view.frame = self.masterView.bounds;
[_masterViewController willMoveToParentViewController:nil];
[self addChildViewController:controller];
self.view.userInteractionEnabled = NO;
[self transitionFromViewController:_masterViewController
toViewController:controller
duration:0.0
options:UIViewAnimationOptionTransitionNone
animations:^{}
completion:^(BOOL finished) {
self.view.userInteractionEnabled = YES;
[_masterViewController removeFromParentViewController];
[controller didMoveToParentViewController:self];
_masterViewController = controller;
}
];
}
}
Here is where #2 is set:
- (void)viewWillLayoutSubviews
{
CGRect contentFrame = self.view.bounds;
float contentWidth = contentFrame.size.width;
CGRect masterRect = contentFrame;
CGRect detailRect = contentFrame;
CGRect dividerRect = contentFrame;
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
masterRect.size.width = DEFAULT_SPLIT_POSITION;
detailRect.origin.x = DEFAULT_SPLIT_POSITION + DEFAULT_DIVIDER_WIDTH;
detailRect.size.width = contentWidth - (DEFAULT_SPLIT_POSITION + DEFAULT_DIVIDER_WIDTH);
dividerRect.size.width = DEFAULT_DIVIDER_WIDTH;
dividerRect.origin.x = DEFAULT_SPLIT_POSITION;
}
else {
masterRect.size.width = contentWidth;
detailRect.origin.x = contentWidth;
dividerRect.origin.x = contentWidth;
}
self.masterView.frame = masterRect;
self.detailView.frame = detailRect;
self.dividerView.frame = dividerRect;
}
[Edited]
So can you update your code with the following so that you call all of the view container containment methods are used and called in the correct order.
[MCIPadRootViewController getIPadRootViewController].mcWebViewController.view.frame = CGRectMake(0, 0, self.mcWebViewContainerView.frame.size.width, self.mcWebViewContainerView.frame.size.height);
[self addChildViewController:[MCIPadRootViewController getIPadRootViewController].mcWebViewController];
[self.mcWebViewContainerView addSubview:[MCIPadRootViewController getIPadRootViewController].mcWebViewController.view];
[controller didMoveToParentViewController:self];
Also I don't think your CGRectMake is correct. You normally wouldn't reference the view's frame, you would reference the parent view's bounds. Try setting it like this and see if it helps. That will have it fill the parent view but you can also tweak it.
[MCIPadRootViewController getIPadRootViewController].mcWebViewController.view.frame = self.mcWebViewContainerView.bounds;
I came up with my Own solution.
The problem is my application opens in Landscape mode So i converted my view frame to bounds.
[[[self recurringListController] view] setFrame:[[self view] bounds]];
Using the above method I overcome my issue.
My universal app uses NIBs for its settings screens. I'd like to use the same NIBs for both iPhone and iPad.
Thus on iPad, I use a UIPopoverController in the MainViewController and for settings, simply display the iPhone-sized NIBs, to show what is called the SettingsViewController. The popover is sized 320x460 points.
This causes a problem, because the iPhone version draws a number of things above the status bar programmatically, and for the iPad version this is not necessary. Current situation on iPad:
As you can see, there's a big empty space above the "Settings" title. Thus what I want, is to shift the view controller up about 20 points, inside the popover:
The popover is instantiated as follows in the MainViewController:
settingsPopoverController = [[UIPopoverController alloc] initWithContentViewController:popoverNavigationController];
settingsPopoverController.popoverContentSize = CGSizeMake(320, 460);
settingsPopoverController.delegate = self;
popoverNavigationController.navigationBarHidden = YES;
In the SettingsViewController, I set the frame as follows:
- (void)viewDidLoad
{
self.contentSizeForViewInPopover = CGSizeMake(320, 460);
}
And later in the SettingsViewController, I try to create an offset as follows:
- (void)viewWillLayoutSubviews
{
// shift it up
CGRect frame = self.view.frame;
frame.origin.y = -20;
[self.view setFrame:frame];
}
This does not shift the content up a bit. How to go about?
To clarify: I want to move down the "viewport" that the popover shows.
Try to:
myPopover.autoresizingMask=UIViewAutoresizingNone;
Or:
myPopover.autoresizingMask=UIViewAutoresizingFlexibleHeight || UIViewAutoresizingFlexibleWidth;
You can also try to put your code in -(void)viewDidLayoutSubviews method.
If this answers did not help, try set popoverLayoutMargins (property) instead of setFrame: for example:
popover.popoverLayoutMargins=UIEdgeInsetsMake (
CGFloat 50, //top
CGFloat 50,//left
CGFloat 50,//bottom
CGFloat 50//right
);
I want to create a View outside of the visible screen and push in it (like the default pushViewController animation), but I cannot create the UIView outside. I was trying this code here, but it doesn't work. The View gets always created and displayed in the current UIScreen bounds. That means instead of both views, the one to get pushed out and the one to get pushed in, only the view that goes out "moves", the new view just sits at it's place.
In the the .m of the view to show:
- (void)viewDidLoad
{
[super viewDidLoad];
// set the views frame off the screen
self.view.frame = CGRectMake(320, 0, 320, 460);
}
In the method that actually does the transition:
-(void)showOverview:(UIViewController *)sender //sender = mapviewController
{
NSLog(#"overview");
// current view (frame) = mapviewCOntroller.view
CGRect outFrame = self.view.frame;
if (!self.overviewViewController) {
self.overviewViewController = [[UCOverviewViewController alloc] init];
self.overviewViewController.transitionDelegate = self;
// create a new View for the overview
[self.overviewViewController.view setCenter:self.view.center];
[self.view.window addSubview:self.overviewViewController.view];
[self.view.window bringSubviewToFront:self.mapViewController.view];
}
CGRect inFrame = self.overviewViewController.view.frame;
outFrame.origin.x = outFrame.origin.x-outFrame.size.width;
inFrame.origin.x = self.view.frame.origin.x;
[UIView animateWithDuration:0.5f animations: ^{
[self.view setFrame:outFrame];
}];
}
EDIT: this is my final code, at least the important part. Now, the view thats currently visible gets slider off screen at the same time the off-screen view gets slide in.
-(void)showOverview
{
if (!self.overviewViewController) {
NSLog(#"OverviewViewController created!");
self.overviewViewController = [[UCOverviewViewController alloc] init];
self.overviewViewController.transitionDelegate = self;
// add the subView
[self.view addSubview:self.overviewViewController.view];
[self.view sendSubviewToBack:self.overviewViewController.view];
}
CGRect outFrame = self.mapViewController.view.frame;
CGRect inFrame = self.overviewViewController.view.frame;
outFrame.origin.x -= outFrame.size.width;
inFrame.origin.x = self.view.frame.origin.x;
self.isOverviewViewVisible = YES;
[UIView animateWithDuration:0.5f animations: ^{
[self.mapViewController.view setFrame:outFrame];
[self.overviewViewController.view setFrame:inFrame];
}];
}
your problem is this line.
self.overviewView = self.overviewViewController.view;
You're overriding the view you created with the view you already have.
the following is not a great way to do it but it should work with what I think you have.
- (void)viewDidLoad {
self.overviewViewController.view.frame = CGRectMake(320, 0, 320, 460);
self.overviewViewController.view.backgroundColor = [UIColor blueColor];
}
Then you want another action to do the animations.
[UIView animateWithDuration:0.5f animations: ^{
self.overviewViewController.view.frame = CGRectMake(0,0,320,460);
}];
There are weird and incorrect things in your code that make it confusing to understand what is actually going on, but... forget about using the window anywhere. The only thing you need to worry about, is this. Say View A is your main view. View B is the view you want outside and to come in over A. Then, create B either from nib or manually, add it as a subview to view A, and before you enter the animation block to move it into place, make sure that the current frame is set to {ViewA.bounds.size.width, 0, ViewB.bounds.size.width, ViewB.bounds.size.height}. Assuming you want it to come in from the top right.
I am writing an iPad app that needs to know the usable area of the view for drawing purposes. The view is added into a Navigation controller, so I have the status bar plus the navigation controller both taking up a certain number of pixels. My app happens to be in landscape mode, although I don't think that's relevant.
I am able to get the correct view size AFTER rotation using didRotateFromInterfaceOrientation. But I can't figure out how to do it without the screen being rotated.
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
NSLog(#"drfi %d %d", (int)self.view.frame.size.width, (int)self.view.frame.size.height);
}
^^ that works after rotation. Not before. Can't figure out how to get accurate numbers. And I REALLY don't want to hard wire this.
I will also need this function to be device independent -- it should work on the NEW iPad as well as the older iPad resolutions. I can handle the scaling issues once I know the exact usable area. Why is this so hard? Help!!
I don't think you need to specify your frame's view within the didRotateFromInterfaceOrientation what i will suggest instead is setting some properties to your view autoresizing mask so that it automatically resize itself according to your view orientation.
By setting this for example to your view when your view is loaded (viewDidLoad method):
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
you specify that your view will change its width and height automatically and can get the right values you need to get from there.
You should read this: http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1
for a better understanding of views in iOS
EDIT
Also you probably want to spot what is the orientation of your device which can be accomplish with [[UIApplication sharedApplication] statusBarOrientation];
Your application looks like: there is a start up view, then in this view you will load and add a main view into window, right? Then you should do as below in your main view:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
CGRect frame = self.view.frame;
frame.origin.y = frame.origin.y + 20.0;
self.view.frame = frame;
}
return self;
}
Try this.
CGRect frame = [UIScreen mainScreen].bounds;
CGRect navFrame = [[self.navigationController navigationBar] frame];
/* navFrame.origin.y is the status bar's height and navFrame.size.height is navigation bar's height.
So you can get usable view frame like this */
frame.size.height -= navFrame.origin.y + navFrame.size.height;
You can get this dynamically by combining an instance method with a category method:
Instance method:
This assumes that your view controller (self) is embedded within a navigation controller.
-(int)getUsableFrameHeight {
// get the current frame height not including the navigationBar or statusBar
return [MenuViewController screenHeight] - [self.navigationController navigationBar].frame.size.height;
}
Class category method:
+(CGFloat)screenHeight {
CGFloat screenHeight;
// it is important to do this after presentModalViewController:animated:
if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortrait ||
[[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortraitUpsideDown){
screenHeight = [UIScreen mainScreen].applicationFrame.size.height;
} else {
screenHeight = [UIScreen mainScreen].applicationFrame.size.width;
}
return screenHeight;
}
The above will consistently give you the usable frame height after the status bar and navigation bar have been removed, in both portrait and landscape.
Note: the class method will automatically deduct the 20 pt for the status bar - then we just subtract the navigation header variable height (32 pt for landscape, 44 pt for portrait).