iOS presentModalViewController not allowing previous views to show through - uiview

I am using presentModalViewController to try and display a UIView on top of some other views. I call presentModalViewController from controller1. I am trying to display views from controller2.
From controller1 I call controller2 as follows:
- (void) someButtonPressed: (id)sender
{
MyController* controller2 = [ [ MyController alloc ] initWithNibName:nil bundle:nil ];
[self presentModalViewController:controller2 animated:YES];
//[self presentViewController:controller2 animated:NO completion:nil ];
}
In controller2 I then do this:
- (void)viewDidLoad
{
[super viewDidLoad];
if (YES){
UIWindow* keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView* master = (UIView*)[keyWindow viewWithTag:100]; // Master is the entire app, but always oriented so top left corner is 0,0.
UIView* newView = [ [ UIView alloc ] initWithFrame:CGRectMake(100, 100, 400, 400) ];
[self setView:newView ];
self.view.backgroundColor = [ UIColor clearColor ];
}
}
The problem is that none of the content from the first controller shows through. I want the previous views to remain visible. Is there any way to make the views from the second controller clear of invisible? The reason I want to do this is because I want the second controller/view to display a transparent layer that will catch all touch events without them getting through to the views managed by controller1.
Thanks very much.

Add the view as a sub view, that will work:
- (void) someButtonPressed: (id)sender
{
MyController* controller2 = [ [ MyController alloc ] initWithNibName:nil bundle:nil ];
[[self view] addSubview:[controller2 view]];
// [controller2 release] if you aren't using ARC
//[self presentModalViewController:controller2 animated:YES];
//[self presentViewController:controller2 animated:NO completion:nil ];
}
If you are using viewDidAppear in controller2, place this line after the addSubView line:
[controller2 viewDidAppear:NO]
Same goes for other viewDid methods ;)

Related

ios - How can I dismiss(close) the load UIViewController on the window

I have a question, I want to build popup view like the UIAlertView,
I create two UIViewController in the storyboard(note: there are not segue),and Root UIViewController will load the UIViewController view popup.
I create two UIViewController to edit the UIView, because I want to use the storybaord to edit my complex UIView in the feature.
Then I put the container view on the RootViewController and there are two button in the container view.(my structure as below:)
When I click the pop up green button(with button name popupGreenBtn), It can correct addSubview on the UIWindow.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"ContainerViewController view didload");
appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
secondGreenVC = (SecondGreenViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"SecondGreenViewController"];
thirdRedVC = (ThirdRedViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:#"ThirdRedViewController"];
}
- (IBAction)popupGreenBtnAction:(id)sender {
[appDelegate.window addSubview: secondGreenVC.view];
[appDelegate.window bringSubviewToFront:secondGreenVC.view];
}
- (IBAction)popupRedBtnAction:(id)sender {
[appDelegate.window addSubview: thirdRedVC.view];
[appDelegate.window bringSubviewToFront:thirdRedVC.view];
}
When I click the button , it can correct popup on the window:
But now , When I click the SecondGreenViewController and ThirdRedViewcontroller background view(just transparent dark black), I want to close the popon the view(secondGreenVC.view or thirdRedVC.view).
I had try to add the code in the SecondGreenViewController class below:
#implementation SecondGreenViewController
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction:)];
[_secondBaseView addGestureRecognizer:tap];
}
-(void) tapAction:(UITapGestureRecognizer*) recognizer
{
[self removeFromParentViewController];
// [self dismissViewControllerAnimated:NO completion:nil];
NSLog(#"tap in SecondGreenViewController");
}
#end
There are not effect to close the UIViewController.
How can I close the Popup window(the UIViewController) when I click the dark black part?
(If you want to more info, please tell me or you can see my this simple project from github https://github.com/dickfalaDeveloper/PopUpViewDemo )
Thank you very much.
-(void) tapAction:(UITapGestureRecognizer*) recognizer
{
thirdViewcontroller.hidden=YES;
}
I resolve the problem. But I don't know have any best answer.
My method is in the popupGreenBtnAction actin.
change the code to:
appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
secondGreenVC.modalPresentationStyle = UIModalPresentationCustom;
[appDelegate.window.rootViewController presentViewController:secondGreenVC animated:NO completion:nil];
Then in the SecondGreenViewController storyboard,
Drag an other UIView do base UIView and set the UIView IBOutlet(now I name with"secondBaseView").
at SecondGreenViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction:)];
[self.secondBaseView addGestureRecognizer:tap];
}
-(void) tapAction:(UITapGestureRecognizer*) recognizer
{
[self dismissViewControllerAnimated:NO completion:nil];
}
That is Ok to show the modal and dismiss the modal UIViewController.

Present UIWebview on top on currently displayed view controller

I'm trying to modally display a UIWebview on top of the currently displayed view controller. The code to popup the webview lives in a static library and has no idea about the view controller hierarchy of the app that it lives in. The code below works for my test cases, but not sure if it would work for all possible view controller hierarchies.
UIViewController *rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
UIViewController *presentedVC = [rootViewController presentedViewController];
if (presentedVC) {
// We have a modally displayed viewcontroller on top of rootViewController.
if (!presentedVC.isBeingPresented) {
[presentedVC presentViewController:vc animated:YES completion:^{
//
}];
} else {
rootViewController presentViewController:vc animated:YES completion:^{
//
}];
}
Does the presentedViewController always give the currently visible view controller?
If what you want to do is to display the UIWebView modally on top of whatever View Controller is displayed in your app, you don't need the "topmost" one. Getting the Root View Controller will suffice. I do this all the time whenever I want to present a View on top of everything else.
You only need a reference to the root view controller in your library:
self.rootVC = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
Having this reference you have two options now:
The first one is to use UIViewController's method presentViewController:animated:completion: to display another View Controller which will contain your UIWebView
The second option is to fake the modal view controller by adding a subview that covers the entire screen, has a (semi)transparent background, and contains the view you want to display "modally". Here is an example:
#interface FakeModalView : UIView // the *.h file
#property (nonatomic, retain) UIWebView *webView;
#property (nonatomic, retain) UIView *background; // this will cover the entire screen
-(void)show; // this will show the fake modal view
-(void)close; // this will close the fake modal view
#end
#interface FakeModalView () // the *.m file
#property (nonatomic, retain) UIViewController *rootVC;
#end
#implementation FakeViewController
#synthesize webView = _webView;
#synthesize background = _background;
#synthesize rootVC = _rootVC;
-(id)init {
self = [super init];
if (self) {
[self setBackgroundColor: [UIColor clearColor]];
_rootVC = self.rootVC = [[[[[UIApplication sharedApplication] delegate] window] rootViewController] retain];
self.frame = _rootVC.view.bounds; // to make this view the same size as the application
_background = [[UIView alloc] initWithFrame:self.bounds];
[_background setBackgroundColor:[UIColor blackColor]];
[_background setOpaque:NO];
[_background setAlpha:0.7]; // make the background semi-transparent
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(THE_POSITION_YOU_WANT_IT_IN)];
[self addSubview:_background]; // add the background
[self addSubview:_webView]; // add the web view on top of it
}
return self;
}
-(void)dealloc { // remember to release everything
[_webView release];
[_background release];
[_rootVC release];
[super dealloc];
}
-(void)show {
[self.rootVC.view addSubview:self]; // show the fake modal view
}
-(void)close {
[self removeFromSuperview]; // hide the fake modal view
}
#end
If you have any other questions just let me know.
Hope this helps!

Nice slide transition between non-fullscreen and fullscreen UIViewController

I have a view controller which is not fullscreen (has a status bar) and want to present a modal view controller which is fullscreen.
If I hide the status bar at the beginning of the animation (parent's viewWillDisappear or modal's viewWillAppear) then for a moment the parent will be visible without a status bar, looking like a bug.
If I do it at the end of the animation (parent's viewDidDisappear or modal's viewDidAppear) then the status bar will be visible for a moment over the modal view, i.e. it won't appear as the modal view "covered it".
Is there a way to do this nicely?
edit:
One possibility would be to create a UIWindow with windowLevel=alert for at least the duration of the animation. The sample iAd ad seems to cover the status bar nicely without another window, so it must be possible somehow.
Another fun little project. This was the best I could come up with. It's not too bad if you don't mind using your own container controller to manage presenting/dismissing view controllers. I try to do things in a general way but this could be rolled into an app w/ the ContainerViewController if desired.
Note that I only implemented the equivalent of UIModalTransitionStyleCoverVertical. You can customize the animation however you like as well.
Relevant animation code:
- (void)presentViewController:(UIViewController *)viewControllerToPresent
{
// do nothing if no controller
if (!viewControllerToPresent) return;
[__viewControllers addObject:viewControllerToPresent];
CGRect toFrame = viewControllerToPresent.view.frame;
toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
viewControllerToPresent.view.frame = toFrame;
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionNone
animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:viewControllerToPresent.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
[self.view addSubview:viewControllerToPresent.view];
viewControllerToPresent.view.frame = [UIScreen mainScreen].applicationFrame;
}
completion:nil];
}
- (void)dismissViewController
{
// nothing to dismiss if showing first controller
if (__viewControllers.count <= 1) return;
UIViewController *currentViewController = [__viewControllers lastObject];
UIViewController *previousViewController = [__viewControllers objectAtIndex:__viewControllers.count - 2];
[UIView transitionWithView:self.view
duration:0.2
options:UIViewAnimationOptionTransitionNone
animations:^{
[[UIApplication sharedApplication] setStatusBarHidden:previousViewController.wantsFullScreenLayout withAnimation:UIStatusBarAnimationSlide];
CGRect toFrame = currentViewController.view.frame;
toFrame.origin = CGPointMake(0, CGRectGetMaxY(self.view.bounds));
currentViewController.view.frame = toFrame;
}
completion:^(BOOL finished) {
[currentViewController.view removeFromSuperview];
[__viewControllers removeLastObject];
}];
}
I do that in my app with this code:
[[UIApplication sharedApplication] setStatusBarStyle: UIStatusBarStyleBlackOpaque];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation: UIStatusBarAnimationSlide ];
DocumentListViewController * dl = [[DocumentListViewController alloc] initWithNibName:#"DocumentListView" bundle:nil] ;
UINavigationController * nav = [[UINavigationController alloc] initWithRootViewController:dl];
[dl release];
// Go to the list of documents...
[[self.view superview] addSubview:nav.view];
nav.view.alpha = 0.0 ;
[self hideActivityAlert];
[UIView animateWithDuration:1.0 animations:^{
nav.view.alpha = 1.0; } completion:^(BOOL A){
[self.view removeFromSuperview];
[self release];} ];
The status bar is presented shoftly while the animation occurs.
You have to be sure that the first view, when status bar is going hidden will fill the space. Use the property autoresizingMask with proper value.
Here's a solution that seems to work. You can derive the viewcontroller you want to present modally from my TSFullScreenModalViewController, or you can just implement the code right in the view controller itself.
#interface TSFullScreenModalViewController : UIViewController
{
UIWindow* _window;
}
- (void) presentFullScreenModal;
#end
#implementation TSFullScreenModalViewController
- (void) viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear: YES];
[_window resignKeyWindow];
[_window release];
_window = nil;
}
- (void) presentFullScreenModal
{
UIViewController* rvc = [[UIViewController new] autorelease];
rvc.view.backgroundColor = [UIColor clearColor];
_window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds] ;
_window.windowLevel = UIWindowLevelStatusBar+1;
_window.backgroundColor = [UIColor clearColor];
_window.rootViewController = rvc;
[_window makeKeyAndVisible];
[UIApplication sharedApplication].statusBarHidden = YES;
[rvc presentModalViewController: self animated: YES];
[UIApplication sharedApplication].statusBarHidden = NO;
}
#end
Derive your modal view controller, like this:
#interface MyModalViewController : TSFullScreenModalViewController
{
}
- (IBAction) onDismiss:(id)sender;
#end
Use it from another view controller, like this:
- (IBAction) onShowModal:(id)sender
{
MyModalViewController* mmvc = [[MyModalViewController new] autorelease];
[mmvc presentFullScreenModal];
}
Finally, dismiss your view controller as you normally would:
- (IBAction) onDismiss:(id)sender
{
[self dismissModalViewControllerAnimated: YES];
}
Might be a bit of a hack but have you considered:
Take a screenshot programatically of the first view with the status bar (see this SO question)
Create a new view which displays the image you just took in fullscreen (using UIImage's initWithFrame)
Hide the status bar
Present the modal view controller
Then to dismiss the modal view, just reverse the steps.
EDIT:
Won't work for this because you can't take screenshots of the status bar.
It could be as simple as delaying the presentation of your modalViewController using performSelector:withDelay:
Tell the status bar to animate out and then launch the modal controller with the right delay so it coincides with the status bar animation.

ipad UIPopoverController with UINavigationController

How can I create a UIPopoverController with integrated UINavigationController so I will be able to slide views inside the UIPopoverController left-right (with navigation bar).
UPDATE:
I open popup like this
- (void)showSettingsViewAtSenderForIPad:(id)sender
{
if (!settingsPopoverController_)
{
SettingsPopoverController *settings = [[SettingsPopoverController alloc] init];
settings.valuesGeneratorOptions = valuesGeneratorOptions_; // setting variables
self.settingsPopoverController_ = [[[UIPopoverController alloc] initWithContentViewController:settings] autorelease];
[settingsPopoverController_ setDelegate:self];
[settingsPopoverController_ setPopoverContentSize:CGSizeMake(320, 480)];
[settings release];
}
if (!infoPopoverController_.popoverVisible)
{
[settingsPopoverController_ presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}
}
I created a controller which has a NSTableViewController as a root controller in UINavigationController
#interface SettingsPopoverController : UIViewController
{
ValuesGeneratorOptions *valuesGeneratorOptions;
IBOutlet SettingsViewController *settingsViewController;
IBOutlet UINavigationController *navigationController;
}
...
#implementation SettingsPopoverController
...
- (void)viewDidLoad
{
self.settingsViewController.valuesGeneratorOptions = self.valuesGeneratorOptions;
[self.view addSubview:self.navigationController.view];
[super viewDidLoad];
}
...
end
The problem is, that the table is not scrollable inside the popup. It also ignores the table style (initWithStyle not called).
Fix?
SOLUTION:
Found the solution: popOver table view
You create a new nib and a UIViewController. This nib has, as it's top level view, a plain jane UIView and a UINavigationController. The UINavigationController's top UIViewController is whatever view controller you want to display first.
You then display this nib inside your popover controller. In the view did load, you do something like this:
-(void)viewDidLoad
{
[self.view addSubview:self.navigationController.view];
}
This adds your navigation controller's view to your view in your nib, which allows it to be displayed.

Changing viewController on Button Click

I am new to iPhone programming. what I am trying is I have one screen with a button. And I want to change the view controller not only the view when I click that button (I know how to add subview) because from that 2nd view controler, I have to go to the third view which is not possible if I add subview in first place. Can anybody please help me with that? Is this possible? and if yes, how? All the views and view controller are created programmaticaly. I am not using IB.
EDIT: here is the relevant code that fires when clicking button
-(id)showCurrentLoc:(id)sender {
locationController = [currentLocController alloc];
[entry removeFromSuperview];
[newLoc removeFromSuperview];
[currentLoc removeFromSuperview];
[self.view setBackgroundColor:[UIColor clearColor]]; //[self.view addSubview: [locationController view]];
[self.navigationController pushViewController:locationController animated:YES]; [locationController release];
return 0;
} //Location Controller is the tableViewController
Thanks
Vik
You can do something like this
YourViewController *objYourViewController = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];
[self.navigationController pushViewController:objYourViewController animated:YES];
[YourViewController release];
Usually, you use a navigation controller for this sort of thing so that the user can easily go back to the previous view. Your view controller would then do something like this:
[self.navigationController pushViewController:someNewViewController animated:YES];
If you want to manage the view controllers yourself, you can always just change the window's rootViewController property. Please read View Controller Programming Guide for the complete picture.
UINavigationController is what you need. It manages a stack of UIViewControllers and if you want to add new UIViewController just push it into this navigation stack. It automates back button behavior for you, and you can pop your current UIViewController from stack whenever you are done with it.
You could work with a UINavigationController. Adding your first UIViewController like this in the init method:
[self setViewControllers:[NSArray arrayWithObject:viewController]];
And then when a button is click or a choice is made, your push the second few controller with (in the first viewController):
[self.navigationController pushViewController:controller animated:YES];
This way you will also get an automatic (back button). Basicly you create a stack of UIViewControllers that you can push and pop like with a normal stack.
I hope this helps. Look into the following:
UINavigationController Class Reference
- (void) loadViewAtIndex:(NSInteger)index {
[self unloadViewAtIndex:activeViewIndex];
switch (index) {
case 1:
{
if (viewController1 == nil)
{
viewController1 = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil];
}
viewController1.view.frame = CGRectMake(0.0, 0.0, viewController1.view.frame.size.width, viewController1.view.frame.size.height);
[window addSubview:viewController1.view];
}
break;
case 2:
{
if (viewController2 == nil)
{
viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
}
viewController2.view.frame = CGRectMake(0.0, 0.0, viewController2.view.frame.size.width, viewController2.view.frame.size.height);
[window addSubview:viewController2.view];
}
break;
default:
break;
}
activeViewIndex = index;
}
- (void) unloadViewAtIndex:(NSInteger)index {
switch (index) {
case 1:
{
if (viewController1 != nil)
{
[viewController1.view removeFromSuperview];
[viewController1 release];
viewController1 = nil;
}
}
break;
case 2:
{
if (viewController2 != nil)
{
[viewController2.view removeFromSuperview];
[viewController2 release];
viewController2 = nil;
}
}
break;
default:
break;
}
}

Resources