I wanted to create a modal view controller with a black background, but I want to make the alpha as 0.9, so I can still see the view behind it partially. How do I do this? I know I can use UIView and then just add that as a subview, however if I have a UINavigationController or UITabBarController, this won't cover the entire screen. Looking for some suggestions on this, as far as I know the solutions I've seen so far never dealt with a colored background.. most only wants a transparent background.
This will help you...
You just have to set background color as per your requirement.
Did you try
[viewController1 presentModalViewController:viewController2 animated:YES];
I haven't tried it myself but the documentation says it always presents it full screen. Then just set its view to have a backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.9];. (white = 0.0 is black). Add whatever subviews you want. Or set the background color to be full black and the alpha of the whole view to be 0.9. It depends if you want the subviews also to be a bit translucent.
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.
First add an UIImageView in you .h file
UIImageView *overLayImage;
now add below code in .m file on viewDidLoad()
overLayImage=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"overlay1px.png"]] ;
overLayImage.frame = self.view.frame;
overLayImage.frame = CGRectMake(0, 0, 1024, 748);
Where "overlay1px.png" is a transparent image of your color choice with height and width of 1px X 1px.
Now in your IBAction from where you want add your view with transparent backgroud add the below code
[self.view addSubview:overLayImage];
[vwTermsCondition setFrame:CGRectMake(262, 300, 500, 120)];
[vwTermsCondition.layer setCornerRadius:5.0f];
[vwTermsCondition.layer setShadowColor:[UIColor blackColor]];
[vwTermsCondition.layer setMasksToBounds:YES];
[self.view addSubview:vwTermsCondition];
In the above code vwTermsCondtion is the name of your view. This is for iPad appplication you can adjust height/width for iPhone.
Enjoy :)
Related
I've added a UIView (which contains the UIImageView for the background, three UIButtons which say "Test" and the final UIButton to dismiss the view called "Finished") as a subview of my UIActionSheet.
Why won't any of these buttons detect touches? My UIView has User Interaction Enabled checked.
I'd appreciate some help with this as I've been pulling my hair out (not literally of course)!
Here's my set up:
If you're just looking mimic the UIActionSheet, I'd just create a UIVew subclass called something like "CoolActionSheet" and programatically place the buttons on there. Then, when you press the buttons it triggers a delegate method in a protocol which will be implemented in your main view controller so do something.
To show and hide the action picker use UIView animations in the CoolActionSheet class like so:
-(void)showSheet {
NSLog(#"Showing sheet...");
//Set the x/y position of the action sheet to JUST off-screen
CGFloat xPos = parentView.frame.origin.x;
CGFloat yPos = parentView.frame.size.height+kActionSheetHeight;
[self setFrame:CGRectMake(xPos, yPos, kActionSheetWidth, kActionSheetHeight)];
/*Here is where you would add your other UI objects such as buttons
and set their #selector to a method in your CoolActionSheet protocol. You could then implement this delegate method in
your main view controller to carry out a custom action. You might also want to add a background image to the view or something else.
For example: */
UIButton *coolButton = [[UIButton alloc] initWithFrame:buttonDimensions];
[coolButton addTarget:self action:#selector(didDismissActionSheet) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:coolButton];
[self.parentView addSubview:self.view];
//Slide the sheet up from the bottom of the screen
[UIView animateWithDuration:0.2 animations:^(void) {
//Slide banner in from left to right
[self setFrame:CGRectMake(0, yPos-kActionSheetHeight, kActionSheetWidth, kActionSheetHeight)];
}];
}
And to hide:
-(void)hideSheet {
NSLog(#"Hiding");
CGFloat xPos = parentView.frame.origin.x;
CGFloat yPos = parentView.frame.size.height+kActionSheetHeight;
[UIView animateWithDuration:0.2 animations:^(void) {
[self setFrame:CGRectMake(xPos, yPos, 320, 65)];
}completion:^(BOOL finished) {
[self removeFromSuperview]; //Clean up
}];
}
You may also want to grey-out the parent view. Again, in the CoolActionSheet.m:
-(void)shadeParentView {
UIView *shadedView = [[UIView alloc] initWithFrame:CGRectMake(, 0, 320, 480)];
[shadedView addGestureRecognizer:gestureRecognizer];
[shadedView setBackgroundColor:[UIColor blackColor]];
[shadedView setAlpha:0.0];
[self addSubview:shadedView];
[UIView animateWithDuration:0.5 animations:^{
[shadedView setAlpha:0.5];
}];
}
You would need to set your parentView to the view controller's view. So, to call the action sheet in your main view controller you would:
CoolActionSheet *coolSheet = [[CoolActionSheet alloc] init];
[coolSheet setParentView:self.view];
[coolSheet setSheetDelegate:self]; //set the delegate to implement button press methods in this view controller
This might seem a bit long-winded, but it's a good MVC pattern to separate it out into another view class like this. And you now have a custom class that you can just import into any other project and it'll work!
I haven't had a chance to test out this specific code, but the whole approach is good. Points to take away from this:
Use a custom UIView class
Implement delegate methods to execute tasks in your main view controller when a button is pressed in your subview.
Implement a good MVC structure to avoid spaghetti code.
Let me know if this helps :)
Try This:
[actionSheet showInView:self.view.window];
I have made a custom UIView which is shown when the user hits a button in the navigationbar. I make my view's in code. In my loadview I set the autoresizing masks and the view loads correct on screen. However the UIView which is shown when the user taps the button does not resize even when I have set the autoresizing masks.
UIView *blackView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 416.0)];
blackView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Do I need to use self.view.frame.size.width and self.view.frame.size.height instead? And if I do why? Does not resizing masks work outside of loadView?
Thank you for your time:)
the autoresizingMask affects how a view will behave when its superviews frame changes. if all you are doing is showing theblackViewwhen you tap a button, thenblackView` will have whatever frame you initially set for it.
If this isn't enough info, please post some more code around how you are configuring and displaying blackView and it's superview and explain more about what situations you are expecting blackView to resize in. Rotation is one of them, if that's what you're concerned with.
First things first, I hope you've done this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
Let's say the view that needs resizing is: view2
The view that has view2 as a subview is: view1
While creating view1 you would declare it as:
view1 = [[UIView alloc] init];
[view1 setNeedsLayout];
Now in view1's .m file you need to overload the layoutSubviews method as shown:
- (void)layoutSubviews
{
CGRect frame = view2.frame;
// apply changes to frame
view2.frame = frame;
}
In case view1 is a view controller's view, you need to do that same thing as above in the willRotate method as shown
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
CGRect frame = view2.frame;
// apply changes to frame
view2.frame = frame;
}
This is a tried and tested method that I use to handle orientation changes.
Hey I have a view that has a button that when pressed should modally present a UIDatePicker. I have the picker showing up properly, but because it is on its own UIView, it is full height, and looks funny. All I want is to get a really quick date input from the user, more like a UIActionSheet than a UIView.
How can I make the UIPicker slide up modally only halfway and have some actions on a toolbar, like done etc?
Thanks
You could put it on another UIView which has a transparent background, or more simply, don't use presentModalViewController, but write your own routine to show it in the current view.
// Untested code:
// put this in your current UIViewController (the one where you were going to call presentModalViewController:)
- (void)showPicker:(UIPickerView *) picker{
CGRect startFrame = picker.frame;
CGRect endFrame = picker.frame;
// Set the start position to below the bottom of the visible frame:
startFrame.origin.y = self.view.frame.size.height;
// Set the end position to slid up by the height of the view, so it will just fit:
endFrame.origin.y = startFrame.origin.y - endFrame.size.height;
picker.frame = startFrame;
[self.view addSubView:picker];
[UIView beginAnimations]
picker.frame = endFrame;
[UIView commitAnimations];
}
You would of course need to add all the necessary code to keep a pointer to the picker and keep track of when to show and get rid of it.
Edit 2: When I start the app without the status bar on top everything behaves as planned. With the status bar I couldn't get the views to act as I wanted. It looks as if the UINavigationController keeps resizing the content view by subtracting the 20 pixels of the status bar. I don't know.
I created a simple UINavigationController-based application. The root view in this navigation controller is a UITableView. At a certain time I want to slide in a 80 pixel high view from the bottom. The whole view on the top (the one that is controlled by the UINavigationController) should resize and get 80 pixel smaller to make room for the new bottom view.
This is basically the code I use to repositioning the views:
-(void)showTeaser {
float adHeight = 80;
[adView setFrame:CGRectMake(0.0,self.navigationController.view.bounds.size.height, 320.0, 80.0)];
[[[UIApplication sharedApplication] keyWindow] addSubview:adView];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[adView setAlpha:1.0];
[adView setFrame:CGRectMake(0.0,self.navigationController.view.bounds.size.height-adHeight, 320.0, 80.0)];
[self.navigationController.view setFrame:CGRectMake(0.0,0.0, 320.0, self.navigationController.view.bounds.size.height-adHeight)];
[self.view setFrame:CGRectMake(0.0, 0, 320.0, self.view.bounds.size.height-adHeight)];
[UIView commitAnimations]; }
I lowered the Navigationbar's alpha, set the UITableviewController's view to red. The new view is purple.
This is what happens. First screenshot initial state. Everything is looking normal. Second screenshot shows state after changing the frames. The view of the UITableviewController is always pushed 20 pixel under the Navigationbar. Also, if I try to add more views to the keywindow, they always end up 20 pixel higher than I expect. It almost looks like the keywindow (minus the navigation bar) is pushed up 20 pixel.
Edit 1: No matter to what size I resize the view, it's always 20 pixel.
Do I make a mistake by adding views to the keywindow at all? Shouldn't I do this?
alt text http://www.hans-schneider.de/iphone-seo/1.png alt text http://www.hans-schneider.de/iphone-seo/2.png
To solve this, I made the view of the UINavigationController a subview of a UIView, and manually set the bounds of the view for the `UINavigationController'.
//outerView is a UIView defined in the interface
outerView = [[UIView alloc] initWithFrame:CGRectMake( 0.0, 0.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);];
//mainNavigationController is a UINavigationController defined in the interface
//rootViewController is a UIViewController (or inherited class) defined in the interface and instanced before this code
mainNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
//set the frame for the view of the navigation controller - 20 is due to the status bar
mainNavigationController.view.frame = CGRectMake( 0.0, 20.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 20);
Then later, when I go to resize, I resize the parent 'UIView' rather than the 'UINavigationController' view.
//change the outer view's frame to resize everything
//adHeight is a float defined earlier
outerView.frame = CGRectMake( 0.0, 20.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 20 - adHeight);
This works well in an animation sequence.
Edit 2011-05-12: I updated the outerView frame to fill the screen. This must be set to allow for touch events.
Have you tried using the transform property of your tableview instead of manually changing it's frame? It may work out better, since the frame depends on the origin, and you only want to change it's size.
I'm trying to do something that shouldn't be that complicated, but I can't figure it out.
I have a UIViewController displaying a UITableView. I want to present a context menu when the user press on a row. I want this to be a semi-transparent view with labels and buttons.
I could use an AlertView, but I want full control on the format of the labels and buttons and will like to use Interface Builder.
So I created my small view 250x290, set the alpha to .75 and create a view controller with the outlets to handle the different user events.
Now I want to present it.
If I use presentModalViewController two (undesired) things happen
1) the view covers all of the screen (but the status bar).
2) It is semi-transparent, but what I see "behind" it its not the parent view but the applications root view.
Ive tried adding it as a subview, but nothing happens, so Im not doing something right:
RestaurantContextVC* modalViewController = [[[RestaurantContextVC alloc] initWithNibName:#"RestaurantContextView" bundle:nil] autorelease];
[self.view addSubview:modalViewController.view];
Is it possible to do what I want?
Thanks in advance.
Gonso
I'm coding similar thing. My approach include.....
Not using dismissModalViewControllerAnimated and presentModalViewController:animated.
Design a customized full sized view in IB. In its viewDidLoad message body, set the background color to clearColor, so that space on the view not covered by controllers are transparent.
I put a UIImageView under the controllers of the floating view. The UIImageView contains a photoshoped image, which has rounded corners and the background is set to transparent. This image view serves as the container.
I uses CoreAnimation to present/dismiss the floating view in the modal view style: (the FloatingViewController.m)
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor clearColor]];
[UIView beginAnimations:nil context:nil];
[self.view setFrame:CGRectMake(0, 480, 320, 480)];
[UIView setAnimationDuration:0.75f];
[self.view setFrame:CGRectMake(0, 0, 320, 480)];
[UIView commitAnimations];
}
wangii
Thats pretty much the solution I found.
I load the view with loadNibNamed and then just add it on top with addSubView, like this:
//Show a view on top of current view with a wait indicator. This prevents all user interactions.
-(void) showWaitView{
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:#"WaitView" owner:self options:nil];
#ifdef __IPHONE_2_1
waitView = [ nibViews objectAtIndex: 0];
#else
waitView = [ nibViews objectAtIndex: 1];
#endif
CGFloat x = self.view.center.x - (waitView.frame.size.width / 2);
CGFloat y = self.view.center.y - (waitView.frame.size.height / 2);
[waitView setFrame:CGRectMake(x,y,waitView.bounds.size.width,waitView.bounds.size.height)];
[self.view addSubview:waitView];
}
Could you elaborate on points 3 and 4?
What I did to give the view the round rect aspect is put it inside a round rect button.
This code will actually allow you to have a small floating view, but if the view is smaller that its parent, the user could interact with the visible part of the parent.
In the end I create my view with the same size, but kept the code just in case.
Gonso
I would strongly consider using a navigation controller to slide in your subview instead of overlaying it. This is the expected model and any small benefit you may think you'll get by doing it your own way will be greatly offset by the principle of (least) surprise.
If you really really have to do it this way, I believe the trick is to add the first table view as a subview of a transparent "holding" view that the view controller maintains. Then add your new sub view as another subview of that.
Again, if you really want to do this, instead of adding a transparent "holding" view, since this pop-up is essentially modal, I would make it a subview directly of the window.
You might want to put in a transparent black shield behind it to prevent touches on the background and focus input on the popup.
But seriously, consider either popping a controller on the stack or using that alert view. Unless you've hired a $$ designer, it's probably not going to look appropriate on the iPhone.
What I did was create a UIViewController on top of my UINavigation controller in my app delegate and made it a property of a singleton object for convenience:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//--- create root navigation controller
self.window.rootViewController = self.navigationController;
//--- create view controller for popups:
popupViewController = [[BaseViewController alloc] init];
popupViewController.view.backgroundColor = [UIColor clearColor];
popupViewController.view.hidden = true; //for rendering optimisation
[self.window addSubview:popupViewController.view];
[AppState sharedInstance].popupViewController = self.popupViewController;
//--- make all visible:
[self.window makeKeyAndVisible];
return YES;
}
At any point in my app, I can then call e.g.
MyViewController * myVC = [[UIViewController alloc] init];
//... set up viewcontroller and its view...
// add the view of the created view controller to the popup view:
[AppState sharedInstance].popupViewController.view.hidden = false;
[[AppState sharedInstance].popupViewController.view addSubview:myVC.view];
The BaseViewController used on the top just inherits from UIViewController and sets up a full-screen view:
//----- in BaseViewController implementation
- (void)loadView {
//------- create root view:
CGRect frame = [[AppState sharedInstance] getScreenFrame];
rootView = [[VCView alloc] initWithFrame:frame];
rootView.backgroundColor = [UIColor whiteColor];
self.view = rootView;
}