Adding UIView as subview of app's main window - ios

I want to display a UIView on top of other views, no matter what view is currently displayed. So I created the following method in custom class that is not related to any views:
- (void) showLoading {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(100,100, 100, 100)];
[redView setBackgroundColor:[UIColor redColor]];
[[appDelegate window] addSubview: redView];
}
The view is not displayed when the method is called. However it is displayed if I rotate device, so screen orientation is changed. I guess that I should reload view somehow, but at this point I'm stuck. Could you please help me?

Thank you, dtrotzjr, for good question. The problem was that the method was called from background thread. Here is the solution:
dispatch_async(dispatch_get_main_queue(), ^{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(100,100, 100, 100)];
[redView setBackgroundColor:[UIColor redColor]];
[[appDelegate window] addSubview:redView];
});
Sorry for bothering.

You can create a AlertViewController and present that on top of any view controller, you can even make this AlertViewController to be transparent.
self.parentVC = someVC;/*this should be the VC over which you want to present the alert VC */
self.modalPresentationStyle = UIModalPresentationCustom;
[self setTransitioningDelegate:someDelegate];
dispatch_async(dispatch_get_main_queue(), ^{
[self.parentVC presentViewController:self
animated:YES
completion:^{
}];
});

Related

KeyWindow add subView, did not shows in the front

I use keyWindow to add a subView, it add success but did not shows in the front of the screen hierarchy.
The deep gray view is my added view:
My code is:
#interface ViewController ()
{
LMLUpspringView *pop_v;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
pop_v = [[LMLUpspringView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
UIWindow *keywindow = [[[UIApplication sharedApplication] delegate] window];
[keywindow addSubview:pop_v];
//[keywindow bringSubviewToFront:pop_v];
//[self.view addSubview:pop_v];
}
I have tried use [keywindow bringSubviewToFront:pop_v] to bring to front.But do not work.
And if I use [self.view addSubview:pop_v], it shows in the front.
You run into this issue, is caused by you do not know the difference between the viewDidLoad method and the viewDidAppear: method.
viewWillAppear:
Called before the view is added to the windows’ view hierarchy
viewDidAppear:
Called after the view is added to the view hierarchy
The controller's view add to the window's view hierarchy is betweenviewWillAppear: and viewDidAppear:, the viewDidLoad is in front of viewWillAppear:, so you can not do that. you should in viewDidAppear: add your view.
You can solve this problem using appdelegate's Windows :
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.window addSubview:pop_v]
Use this:
#interface ViewController ()
{
LMLUpspringView *pop_v;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
pop_v = [[LMLUpspringView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
UIWindow *keywindow = [[UIApplication sharedApplication] keyWindow];
[keywindow addSubview:pop_v];
//[keywindow bringSubviewToFront:pop_v];
//[self.view addSubview:pop_v];
}

The right way for creating a custom popup / alert UIView / UIViewController

I've been developing for iOS for quite a while now, but I always got problems with custom alerts / popups, I just don't know what is the right way to add a custom view as a popup on top of all other views in app.
I've checked online and there are several ways to do it, but what is the best way for creating those custom alerts / popups?
There is a CustomViewController class and this is how I've created it and add it as a popup:
Create a new UIViewController
Add a UIView inside the UIViewController's XIB file as a child of self.view (This will hold the popup elements inside)
Add this method inside the UIViewController for presenting the view:
- (void)presentViewController
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.windowLevel = UIWindowLevelStatusBar;
self.window.screen = [UIScreen mainScreen];
[self.window makeKeyAndVisible];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:NO];
[self.window addSubview:self.view];
self.view.alpha = 0.0f;
self.backgroundImage.image = [self takeSnapshot];
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
self.view.transform = CGAffineTransformIdentity;
self.view.alpha = 1.0f;
} completion:nil];
}
Add this method inside the UIViewController for removing the view:
- (void)dismissShareViewController
{
[UIView animateWithDuration:DEFAULT_ANIMATION_DURATION
animations:^{
self.view.alpha = 0.0f;
} completion:^(BOOL finished) {
[self.view removeFromSuperview];
self.window = nil;
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
[mainWindow setUserInteractionEnabled:YES];
}];
}
Usage:
Creating a property for the UIViewController
#property (strong, nonatomic) CustomViewController *viewController;
Initialize and present
- (void)showCustomViewController
{
self.viewController = [[CustomViewController alloc] init];
[self.viewController presentViewController];
}
The problem is that I always get a Received Memory Warning. Also I've added a - (void)dealloc method inside the CustomViewController to know if the UIViewController is releasing properly, but for some reason the dealloc method is getting called right after the presentViewController and not after the dismissShareViewController as it should.
Another thing that I want to achieve: This CustomViewController has no UIStatusBar and when I try to present MFMailComposeViewController, I always get the MFMailComposeViewController to show without a UIStatusBar or with white status bar, but I can't change it to default back again. I've tried several question here on StackOverflow but without any luck, it just won't change.
Putting a UIView or UIWindow above Statusbar
Please, for once and for all, someone will help me with it.
UIAlertView is a subclass of UIView. If you wanted to create a custom alert view, I would also subclass UIView so that it is easy to swap out your existing UIAlertView's with your new custom view.
You can place your custom alert view atop your topmost UIWindow to cover everything.
#interface MyAlertView : UIView
- (void)duplicateAllTheFunctionsOfUIAlertViewHere;
#end
#implementation MyAlertView : UIView
- (id)initWithFrame:(CGRectMake)frame {
// add your custom subviews here
// An example of a custom background color:
self.backgroundColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.5];
}
- (void)duplicateAllTheFunctionsOfUIAlertViewHere {
//re-implement all the functionality in your custom ways
}
- (void)show
{
UIView* superview = [UIApplication sharedApplication].keyWindow;
self.frame = superview.bounds;
[superview addSubview:self];
// Do an animation if you want to get fancy
}
#end
Usage in a view controller:
- (void)showAlertView
{
UIView* alertView = [[MyAlertView alloc] initWithTextAndButtons:#"blah"];
[alertView show];
}

In iOS 7, using UIModalPresentationCurrentContext for an animated modal presentation doesn't animate

In iOS 8, when presenting a modal (lets say with a transparent background), we need to set the segue (or the modal) to use the presentation style of UIModalPresentationOverCurrentContext. This is working as expected.
To accomplish the same thing for iOS 7, you instead, need to set the presenting view controller to have a modal presentation style of UIModalPresentationCurrentContext. Here's where I'm having an issue. I present the modal with animation, but it doesn't animate. After it is presented, everything works fine, even animating the dismissal. Further, if I change the presentation style to UIModalPresentationFullScreen, it animates correctly.
I've searched around and read other posts, but I can't find the cause of this or a solution.
ViewController *vcObj = [[ViewController alloc] initWithNibName:NSStringFromClass([ViewController class]) bundle:nil];
UINavigationController *navCon = [[UINavigationController alloc] initWithRootViewController:vcObj];
if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
navCon.providesPresentationContextTransitionStyle = YES;
navCon.definesPresentationContext = YES;
navCon.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:navCon animated:NO completion:nil];
}
else {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[self presentViewController:navCon animated:NO completion:^{
[navCon dismissViewControllerAnimated:NO completion:^{
appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:navCon animated:NO completion:nil];
appDelegate.window.rootViewController.modalPresentationStyle = UIModalPresentationFullScreen;
}];
}];
}

UITableView background does not set

I have this code inside the viewDidLoad (putting that inside the viewDidAppear didn't work either).
UIView *texturedBackgroundView = [[UIView alloc] initWithFrame:self.view.bounds];
texturedBackgroundView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"BackgroundLeather.png"]];
self.tableView.backgroundView = texturedBackgroundView;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
But I cannot see any background as an image. It is completely white - like no image is set. Why is that?
Please note that, my tableview has it's own controller - which is initialised like this :
AppDelegate *del = (AppDelegate*)[[UIApplication sharedApplication] delegate];
PAPHomeViewController *vc = del.homeViewController;
vc.view.frame = self.containerView.bounds;
[self.containerView addSubview:vc.view];
[self addChildViewController:vc];
So, it is like I see the background of the containerView and not the background of the tableview.
Trying that didn't help it :
[self.containerView setBackgroundColor:[UIColor clearColor]];

Presenting a ViewController breaks the previous ViewController

My problem is when I present a UIViewController the presenting views are going black.
I have a UIViewController named mainViewController which is the root view of my windows.
Inside I have a MMDrawerController (just added as a subview of mainViewController's view).
The MMDrawerController contains the rest of my views.
But when I'm presenting a new UIViewController from my mainViewController, the new VC displays well, but when it dismisses it left only black screen behind.
To note the black screen appears when adding (I can see it directly). Not when dismissing.
For testing purpose I did this code :
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
[[[[UIApplication sharedApplication] keyWindow] rootViewController] presentViewController:vc animated:NO completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
Which do the same black result as normal use. (normally it's a QLViewController...)
My mainViewController is set like it :
_mainViewController = [MyMainViewController new];
_window.rootViewController = _mainViewController;
[self.window addSubview:_mainViewController.view];
Souce code of MMDrawerController which is up to date in my project
I have tested the code just in MMDrawerController example project, but I can't reproduce the problem, following is what I have tried:
MMAppDelegate.m
-(BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//...
UIViewController *testVc = [[UIViewController alloc] init];
testVc.view.backgroundColor = [UIColor greenColor];
[testVc.view addSubview:self.drawerController.view];
[self.window setRootViewController:testVc];
[self.window addSubview:testVc.view];
return YES;
}
MMExampleSideDrawerViewController.m:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
switch (indexPath.section) {
case MMDrawerSectionViewSelection:{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
UIViewController *mainVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
[mainVC presentViewController:vc animated:YES completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
return;
//...
}
MMExampleCenterTableViewController.m:
-(void)doubleTap:(UITapGestureRecognizer*)gesture{
UIViewController *vc = [UIViewController new];
vc.view.backgroundColor = [UIColor redColor];
UIViewController *mainVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
[mainVC presentViewController:vc animated:YES completion:^{
[vc dismissViewControllerAnimated:YES completion:nil];
}];
return;
[self.mm_drawerController bouncePreviewForDrawerSide:MMDrawerSideLeft completion:nil];
}
In the end, the problem was that I applied inset constraints on my mainViewController.
Behind the scene I suppose that method presentViewController:animated:completion: use frames and not AutoLayout, which break the UIView of the UIViewController that are in the mainViewController.
Thanks to #simalone, I used the same way to find the origin of the problem (use MMDrawerController example project).
I you want to test yourself the problem, I uploaded the example project with the issue so you can understand it.
There is a breakpoint on the line which is the origin of the bug.
Then just double click on the view.
Thanks again to #simalone. Cheers !

Resources