so i've go a uiviewcontroller (with its default view) that i created programmatically like
TestViewController *aVC = [[MJImageCropViewController alloc] init];
[[self navigationController] pushViewController:aVC animated:YES];
inside it there is something like this in the viewDidLoad
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
the problem is, that the height of the view of the pushedViewController remains 460px but visible is only 416px (because of the existing navigationController.
is there a way to let the uiview of the pushed viewcontroller resize the right way without setting explicit the frame to 416 (because of rotation and so on)?
You may want to try something like this in -viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
// Resize view to account for nav bar
CGFloat navBarHeight = self.navigationController.navigationBar.bounds.size.height;
CGRect frame = self.view.frame;
frame.size.height = frame.size.height - navBarHeight;
self.view.frame = frame;
}
My guess is that the view is being resized correctly, but it's subview's autoresizing masks are not set properly. Also, it makes a lot more sense to place the autoresize code you posted either in loadView (if you are creating the view programmatically) or in the XIB file.
Try to log out the view controller's frame at the end of viewDidLoad via
NSLog(#"%#",NSStringFromCGRect(self.view.frame));
And see what that tells you.
I'm partially through adding a scrollview, by way of instantiating a class that subclasses uiscrollview (below called ScrollViewManager) to override touchesEnded. The problem is although my class now has scrolling and touch, I can't see my view/nib file anymore, even though it's responding to touches and scrolling fine.
My thoughts are to add back the MyClass nib as a subview? or don't know... Seems as though it's there but just hidden behind this scrollView.
The excerpt from 'Myclass : UIViewController ' has these lines of code in viewDidLoad to get the scroll action with touch response.
Thank you so much. So so much.
scrollView = [[ScrollViewManager alloc] initWithFrame:self.view.frame];
scrollView.contentSize = CGSizeMake(320, 600);
[scrollView setUserInteractionEnabled:TRUE];
[scrollView setScrollEnabled:TRUE];
self.view = scrollView;
//trying with this line to add my nib for this class on top of the scroll view
//which doesn't work: 'Accessing unknown 'view' class method'
[scrollView addSubview:Myclass.view];
[scrollView release];
self.view = scrollView line makes your view pointed by view controllers the scrollview.
ie self.view & scrollView now point to same object
after that when you are trying to [scrollView addSubview:Myclass.view]; what actually happening is you are adding scrollView to your scrollView & accessing view property of scrollview.
Just remove the self.view = scrollView line & do this
[self.view addSubView:scrollView];
[scrollView release];
Hopefully it'll work.
for some reason I can't add comments to your post. It didn't work.
Apple talks about adding the subview here: but doesn't explain how. Their code is below for adding the scroll aspect, as I did above. I'm now messing around with trying to add my view as a subview:
UIView *newView = [[NSBundle mainBundle] loadNibNamed:#"MyClassView" owner:self options: nil];
[scrollView addSubview:newView];
but that crashes and goes not where. Don't know what to do now. Apple's code here with original comments:
(void)loadView {
CGRect fullScreenRect=[[UIScreen mainScreen] applicationFrame];
scrollView=[[UIScrollView alloc] initWithFrame:fullScreenRect];
self.view=scrollView;
scrollView.contentSize=CGSizeMake(320,758);
scrollView.contentInset=UIEdgeInsetsMake(64.0,0.0,44.0,0.0);
// do any further configuration to the scroll view
// add a view, or views, as a subview of the scroll view.
// release scrollView as self.view retains it
self.view=scrollView;
[scrollView release];
}
Previously when setting up controllers programatically I have always set the size and position of the root UIView element (i.e.)
// UIViewController -loadView
CGRect viewFrame = CGRectMake(0, 20, 320, 460);
UIView *view = [[UIView alloc] initWithFrame:viewFrame];
[self setView:view];
[view release];
I have just noticed (and I wonder if anyone can confirm) that if your adding the root UIView to a controller that you don't need to set the size or position as it autosizes to the space available. (i.e.)
// UIViewController -loadView
UIView *view = [[UIView alloc] init];
[self setView:view];
[view release];
I understand that subsequent UIViews (i.e. UIButton, UILabel etc.) will need to be positioned and sized, I just want to make sure I am understanding the behaviour I am currently seeing.
It does resize the frame of the view.
UIView *view1 = [[UIView alloc] init];
NSLog(#"ViewFrame before set:%#",NSStringFromCGRect(view1.frame));
[self setView:view1];
NSLog(#"ViewFrame after set:%#",NSStringFromCGRect(view1.frame));
[view1 release];
But I could not find anything in docs that justify this.
Size of the root view of any UIViewController is managed by that controller's parent instance, that may be another controller or window. It determines the size automatically. For example, if you are creating UITabBarController, it determines sizes of all its child controllers' root views. Or, if you write your own container view controller it must determine sizes of root views of its child controllers.
See "View Management" section in this topic:
UIViewController Class Reference
I have a UITableView which is not being resized properly using autoresizeMask (in iPhone 3.0).
The UITableView is inside a UIViewController inside a UINavigationController inside a UITabBarController, all of which are being created programatically. The status bar is visible.
The code of the UIViewController is basically:
- (void)loadView {
UIView* rootView = [[UIView alloc] init];
self.view = rootView;
[rootView release];
}
- (void)viewDidLoad {
[super viewDidLoad];
// table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480-20-49-44)];
table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)]; table.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self.view addSubview:table];
}
When created like this, the UITableView is slightly bigger than the available space. If I'm not mistaken, it's exactly 44 pixels bigger, the size of the navigation bar.
However, if I uncomment the commented line and comment the next line the size of the UITableView is exactly right. I would prefer to use autoresizingMask instead of manually calculating the size of the UITableView. What am I doing wrong?
Thank you in advance!
The problem seems to be that I wasn't setting the frame of the root view in loadView. If you define such frame, and then define the frame of the subviews in relation to that frame, then the autoresize masks will correctly resize the subviews according to how the root view was resized by the framework.
For example:
- (void)loadView {
UIView* rootView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
self.view = rootView;
[rootView release];
}
- (void)viewDidLoad {
[super viewDidLoad];
table = [[UITableView alloc] initWithFrame:self.view.frame];
table.autoresizingMask = UIViewAutoresizingFlexibleHeight;
[self.view addSubview:table];
}
Thanks to Colin Gislason who pointed me in the right direction.
The autoresizing mask will not help you with the initial size of the table view. The table view is created with the frame that you give it. The autoresizing mask defines the rules for resizing this frame relative to the parent view when the parent's frame changes.
So if I define a table that is 320x100 it will stay that size unless I change it explicitly or the parent view's frame changes.
Depending on the other views, you could do the calculation based on the other views held by the parent or by the parent's frame itself.
Create UIViewController subclass instand of UITableViewController Subclass.
insert UITableView instance.
in NIB simply drag and drop UIView
on top of that wier place the existing UITableVIew object.
set the size of the uitableview via nib or viewDidLoad method.
set the reference , dataSource and delegate via nib.
now its simply transfer the UIViewController class and the can change tableview size as you wish.
I'm trying to create a transparent modal View on top of my navigation controller. Does anyone know if this is possible?
A modal view will cover the view it is pushed on top of as well as the navigation bar for your navigation controller. However, if you use the -presentModalViewController:animated: approach, then once the animation finishes the view just covered will actually disappear, which makes any transparency of your modal view pointless. (You can verify this by implementing the -viewWillDisappear: and -viewDidDisappear: methods in your root view controller).
You can add the modal view directly to the view hierarchy like so:
UIView *modalView =
[[[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
modalView.opaque = NO;
modalView.backgroundColor =
[[UIColor blackColor] colorWithAlphaComponent:0.5f];
UILabel *label = [[[UILabel alloc] init] autorelease];
label.text = #"Modal View";
label.textColor = [UIColor whiteColor];
label.backgroundColor = [UIColor clearColor];
label.opaque = NO;
[label sizeToFit];
[label setCenter:CGPointMake(modalView.frame.size.width / 2,
modalView.frame.size.height / 2)];
[modalView addSubview:label];
[self.view addSubview:modalView];
Adding the modalView as a subview to the root view like this will not actually cover the navigation bar, but it will cover the entire view below it. I tried playing around with the origin of the frame used to init the modalView, but negative values cause it to not display. The best method that I found to cover the entire screen besides the status bar is to add the modalView as a subview of the window itself:
TransparentModalViewAppDelegate *delegate = (TransparentModalViewAppDelegate *)[UIApplication sharedApplication].delegate;
[delegate.window addSubview:modalView];
The easiest way is to use modalPresentationStyle property of navigationController (but you'll have to make animation by yourself):
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:modalViewController animated:NO];
modalViewController.view.alpha = 0;
[UIView animateWithDuration:0.5 animations:^{
modalViewController.view.alpha = 1;
}];
I accomplish this most easily by setting up an "OverlayViewController" that sits above all other subviews of my window or root view. Set this up in your app delegate or root view controller, and make OverlayViewController a singleton so that it can be accessed from anywhere in your code or view controller hierarchy. You can then call methods to show modal views, show activity indicators, etc, whenever you need to, and they can potentially cover any tab bars or navigation controllers.
Sample code for root view controller:
- (void)viewDidLoad {
OverlayViewController *o = [OverlayViewController sharedOverlayViewController];
[self.view addSubview:o.view];
}
Sample code you might use to display your modal view:
[[OverlayViewController sharedOverlayViewController] presentModalViewController:myModalViewController animated:YES];
I haven't actually used -presentModalViewController:animated: with my OverlayViewController but I expect this would work just fine.
See also: What does your Objective-C singleton look like?
I had this same problem and in order to The solution is to add the modal view with addSubview: and animate the change in the view hierarchy with UIView’s animateWithDuration:delay:options:animations:completion:
I added a property and 2 methods to a subclass of UIViewController (FRRViewController) that includes other functionalities. I will be publishing the whole stuff on gitHub soon, but until then you can see the relevant code below. For more info, you can check my blog: How to display a transparent modal view controller.
#pragma mark - Transparent Modal View
-(void) presentTransparentModalViewController: (UIViewController *) aViewController
animated: (BOOL) isAnimated
withAlpha: (CGFloat) anAlpha{
self.transparentModalViewController = aViewController;
UIView *view = aViewController.view;
view.opaque = NO;
view.alpha = anAlpha;
[view.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIView *each = obj;
each.opaque = NO;
each.alpha = anAlpha;
}];
if (isAnimated) {
//Animated
CGRect mainrect = [[UIScreen mainScreen] bounds];
CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height);
[self.view addSubview:view];
view.frame = newRect;
[UIView animateWithDuration:0.8
animations:^{
view.frame = mainrect;
} completion:^(BOOL finished) {
//nop
}];
}else{
view.frame = [[UIScreen mainScreen] bounds];
[self.view addSubview:view];
}
}
-(void) dismissTransparentModalViewControllerAnimated:(BOOL) animated{
if (animated) {
CGRect mainrect = [[UIScreen mainScreen] bounds];
CGRect newRect = CGRectMake(0, mainrect.size.height, mainrect.size.width, mainrect.size.height);
[UIView animateWithDuration:0.8
animations:^{
self.transparentModalViewController.view.frame = newRect;
} completion:^(BOOL finished) {
[self.transparentModalViewController.view removeFromSuperview];
self.transparentModalViewController = nil;
}];
}
}
Here's what I did to solve the problem - Google the details but this approach worked very well for me:
Take a screenshot of the underlying view. https://devforums.apple.com/message/266836 - this leads to a ready-made method that returns a UIView for the current screen.
Hand the screenshot to the modal view (I used a property)
Present the modal view
In the modal view controller's viewDidAppear, set the image as UIImageView at index 0. Adjust the vertical position of the image by the height of the status bar.
In the modal view controller's viewWillDisappear, remove the image again
The effect is:
The view animates in as any modal view does - the semi transparent parts of the modal view glide over the existing view
As soon as the animation stops, the background is set to the screenshot - this makes it appear as if the old view is still underneath even though it isn't.
As soon as the modal view's disappear animation starts, the image is removed. The OS meanwhile shows the old navigation view so the modal view transparently glides away and out of sight as you'd expect.
I tried animating in my own overlay view but it didn't work very well. I got a crash with no indication as to what has crashed. Rather than chase this down I did the bg view & Works really well.
Code in the modal view - I think you can figure out the rest, namely setting the property modalView.bgImage...
- (void)viewDidAppear:(BOOL)animated {
// background
// Get status bar frame dimensions
CGRect statusBarRect = [[UIApplication sharedApplication] statusBarFrame];
UIImageView *imageView = [[UIImageView alloc] initWithImage:self.bgImage];
imageView.tag = 5;
imageView.center = CGPointMake(imageView.center.x, imageView.center.y - statusBarRect.size.height);
[self.view insertSubview:imageView atIndex:0];
}
- (void)viewWillDisappear:(BOOL)animated {
[[self.view viewWithTag:5] removeFromSuperview];
}
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:newview animated:YES];
and make sure you setup the modal view background to be transparent,
self.view.background = .... alpha:0.x;
if you set modalPresentationStyle for the modal view controller to:
viewController.modalPresentationStyle = 17;
The view in the background is not removed. (TWTweetComposeViewController use it).
I did not try to pass App Store review with this code though
This post about displaying a semi-transparent "Loading..." view might give a few pointers on how to proceed.
Yeah, you have to add the view manually, and if you want to slide in from the bottom or whatever you have to do the animation yourself too.
I wrote a class to do this, and a semi-modal datepicker using that class as an example.
You can find documentation in this blog post, the code is on github
I've been researching this same issue for the past week. I tried all the various answers and examples found in Google and here on StackOverflow. None of them worked that well.
Being new to iOS programming, I wasn't aware of something called UIActionSheet. So if you're trying to accomplish this in order to show a modal overlay of buttons (such as a modal asking someone how they want to share something), just use UIActionSheet.
Here is a webpage that shows an example of how to do this.
I got this idea from https://gist.github.com/1279713
Prepare:
In the modal view xib (or scene using storyboard), I setup the full-screen background UIImageView (hook it with the .h file and give it a property "backgroundImageView") with 0.3 alpha. And I set the view (UIView) background color as plain black.
Idea:
Then in "viewDidLoad" of the modal view controller I capture the screenshot from the original status and set that image to the background UIImageView. Set the initial Y point to -480 and let it slide to Y point 0 using 0.4-second duration with EaseInOut animation option. When we dismiss the view controller, just do the reverse thing.
Code for the Modal View Controller Class
.h file:
#property (weak, nonatomic) IBOutlet UIImageView *backgroundImageView;
- (void) backgroundInitialize;
- (void) backgroundAnimateIn;
- (void) backgroundAnimateOut;
.m file:
- (void) backgroundInitialize{
UIGraphicsBeginImageContextWithOptions(((UIViewController *)delegate).view.window.frame.size, YES, 0.0);
[((UIViewController *)delegate).view.window.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * screenshot = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
backgroundImageView.image=screenshot;
}
- (void) backgroundAnimateIn{
CGRect backgroundImageViewRect = backgroundImageView.frame;
CGRect backgroundImageViewRectTemp = backgroundImageViewRect;
backgroundImageViewRectTemp.origin.y=-480;
backgroundImageView.frame=backgroundImageViewRectTemp;
[UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^{
backgroundImageView.frame=backgroundImageViewRect;
} completion:^(BOOL finished) {
}];
}
- (void) backgroundAnimateOut{
CGRect backgroundImageViewRect = backgroundImageView.frame;
backgroundImageViewRect.origin.y-=480;
[UIView animateWithDuration:0.4 delay:0.0 options:UIViewAnimationCurveEaseInOut animations:^{
backgroundImageView.frame=backgroundImageViewRect;
} completion:^(BOOL finished) {
}];
}
In viewDidLoad, simply call:
[self backgroundInitialize];
[self backgroundAnimateIn];
In anywhere we dismiss the modal view controller, we call:
[self backgroundAnimateOut];
Please note that this will ALWAYS animate the background image. So if this modal view controller transition style (or the segue transition style) is not set to "Cover Vertical", you may not need to call the animation methods.
I finally accomplished this, for a navigation or tab bar interface, by combining an overlay view controller (see: pix0r's answer) that's hidden / un-hidden before hiding or showing a view controller based on this very good blog post.
Concerning the view controller, the tip is to make its background view the clearColor, then the semi-transparent overlay view is visible and whatever views are added as subviews in the view controller are in front and most importantly opaque.
I've created open soruce library MZFormSheetController to present modal form sheet on additional UIWindow. You can use it to present transparency modal view controller, even adjust the size of the presented view controller.
For iOS 8+ you can use UIModalPresentationOverCurrentContext presentation style for presented view controller to easy achieve desired behavior.
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.9f];
viewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:viewController animated:YES completion:nil];
If you also need to support iOS 7 - check this thread.
You can achieve transparent/semi-transparent modal view effect by overlaying a transparent/semi-transparent button on both the view and the navigation bar.
You can access the navigation bar through the navigationBar property of the UINavigationController.
I found that UIButton unlike UILabel will trap mouse events - hence giving the correct modal behavior.
I just found a workaround for that. Just create a 1X1 of UIViewController and add it to your parent view controller. And show the transparent modal view controller in that UIViewController.
on viewDidLoad;
self.dummyViewController = [[UIViewController alloc] init];
[self.dummyViewController.view setFrame:CGRectMake(0, 0, 1, 1)];
[self.view addSubView:self.dummyViewController.view];
when you need to open a transparentViewController;
[self.dummyViewController presentModalViewController:yourTransparentModalViewController animated:true];
If you need a screen like the attached one, the below code may help you.
The code:
MyViewController * myViewController = [[MyViewController alloc] initWithNibName:nibName bundle:nil];
UINavigationController * myNavigationController = [[UINavigationController alloc] initWithRootViewController: myViewController];
myNavigationController.modalPresentationStyle = UIModalPresentationPageSheet;
[self presentModalViewController: myNavigationController animated:YES];
If say you want a screen overlay, use the parentViewController.view, it will place above navigation bar ++
MyCustomViewController* myOverlayView = [[MyCustomViewController alloc] init];
[self.parentViewController.view addSubview:myOverlayView];
This worked for me:
UIViewController *modalViewController = [[UIViewController alloc] init];
modalViewController.view.backgroundColor = [UIColor whiteColor] colorWithAlpha:0.5];
[self showDetailViewController:modalViewController sender:nil];