I am trying to create a new UIWindow to cover the entire screen, including the status bar. I get it to appear when a button is pressed but it just quickly flashes on the screen and goes away. What am I doing wrong?
MenuTableViewController *menu = [[MenuTableViewController alloc]initWithNibName:#"MenuTableViewController" bundle:nil];
UIWindow *menuWindow = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
menuWindow.backgroundColor = [UIColor clearColor];
menuWindow.windowLevel = UIWindowLevelStatusBar;
menuWindow.rootViewController = menu;
[menuWindow addSubview:menu.view];
[menuWindow makeKeyAndVisible];
menuWindow.hidden = NO;
I got it working by adding #property (nonatomic, strong) UIWindow *menuWindow; to my header file. Here is what my showMenu and closeMenu methods look like.
- (void)showMenu
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
UIButton *closeMenuButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeMenuButton setFrame:CGRectMake(250, 10, 50, 50)];
[closeMenuButton setImage:[UIImage imageNamed:#"close"] forState:UIControlStateNormal];
[closeMenuButton addTarget:self action:#selector(closeMenu) forControlEvents:UIControlEventTouchUpInside];
blurredView = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
[blurredView setBarStyle:UIBarStyleBlack];
MenuTableViewController *menu = [[MenuTableViewController alloc]initWithNibName:#"MenuTableViewController" bundle:nil];
menu.view.frame = CGRectMake(0, 30, screenWidth, screenHeight - 50);
menuWindow = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
menuWindow.backgroundColor = [UIColor clearColor];
menuWindow.windowLevel = UIWindowLevelStatusBar;
menuWindow.rootViewController = menu;
[menuWindow addSubview:blurredView];
[blurredView addSubview:closeMenuButton];
[blurredView addSubview:menu.view];
[menuWindow makeKeyAndVisible];
}
- (void)closeMenu
{
menuWindow.hidden = YES;
menuWindow = nil;
}
Related
I want to create custom navigation bar like WhatsApp uses to display call indicator in the application as given below.
I have successfully added view like above but it's not responsive because I am not able to detect touch on status bar. I can touch only part below "Touch to return to call".
Code is as given below.
#property (nonatomic) UIView *navigationBarTopView;
UIWindow *window = [UIApplication sharedApplication].keyWindow;
if (_navigationBarTopView == nil) {
_navigationBarTopView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, window.frame.size.width, 60.0)];
[_navigationBarTopView setBackgroundColor:[UIColor colorWithRed:76.0/255.0 green:217.0/255.0 blue:100.0/255.0 alpha:1]];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, _navigationBarTopView.frame.size.height - 15, window.frame.size.width, 10)];
[label setText:#"Touch to return to call"];
[label setTextColor:[UIColor whiteColor]];
[label setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
[label setTextAlignment:NSTextAlignmentCenter];
[_navigationBarTopView addSubview:label];
//The setup code (in viewDidLoad in your view controller)
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[_navigationBarTopView addGestureRecognizer:singleFingerTap];
UITapGestureRecognizer *singleFingerTap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[label addGestureRecognizer:singleFingerTap1];
}
[window addSubview:_navigationBarTopView];
I have also tried to add touch on status bar as give below but it doesn't work.
How do I detect touches on UIStatusBar/iPhone
Also navigation bar is not coming downside. I have tried to set keyWindow frame. But that is also not working.
UIStatusBar has higher priority than your application's window, so you won't get any touch event through status bar.
To get touch event through status bar you need a window with higher window level than UIStatusBar.
Try below code:
#import "AppDelegate.h"
#interface AppDelegate ()
#property (nonatomic) UIWindow *buttonWindow;
#property (nonatomic) UIWindow *textWindow;
#property (nonatomic) CGFloat callViewHeight;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
if (#available(iOS 11.0, *)) {
if (([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0)) {
self.callViewHeight = 55.0f;
} else {
self.callViewHeight = 35.0f;
}
} else {
self.callViewHeight = 35.0f;
}
return YES;
}
-(void)showVideoCallButton{
self.textWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
self.textWindow.windowLevel = self.window.windowLevel + 1;
self.textWindow.hidden = FALSE;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
view.backgroundColor = [UIColor colorWithRed:76.0/255.0 green:217.0/255.0 blue:100.0/255.0 alpha:1];
view.clipsToBounds = TRUE;
UILabel *lblName = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
lblName.textAlignment = NSTextAlignmentCenter;
[lblName setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
lblName.text = #"";
UILabel *lblTouch = [[UILabel alloc] initWithFrame:CGRectMake(0, self.callViewHeight - 20.0f, [UIScreen mainScreen].bounds.size.width, 20.0f)];
lblTouch.textAlignment = NSTextAlignmentCenter;
[lblTouch setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
lblTouch.text = #"Touch to return to call";
lblTouch.textColor = UIColor.whiteColor;
[view addSubview:lblTouch];
[view addSubview:lblName];
[self.textWindow addSubview:view];
self.buttonWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, self.callViewHeight)];
self.buttonWindow.windowLevel = UIWindowLevelStatusBar + 1;
self.buttonWindow.hidden = FALSE;
UIButton *button = [[UIButton alloc] initWithFrame:lblName.bounds];
[button setTitle:#"" forState:UIControlStateNormal];
[button addTarget:self action:#selector(buttonTouched) forControlEvents:UIControlEventTouchUpInside];
[self.buttonWindow addSubview:button];
self.textWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
self.buttonWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
[UIView animateWithDuration:0.25
animations:^{
self.textWindow.transform = CGAffineTransformIdentity;
self.buttonWindow.transform = CGAffineTransformIdentity;
if (#available(iOS 11.0, *)) {
if (([[[UIApplication sharedApplication] delegate] window].safeAreaInsets.top > 20.0)) {
self.window.frame = CGRectMake(0, self.callViewHeight - 40.0f, self.window.bounds.size.width, self.window.bounds.size.height - self.callViewHeight + 40.0f);
} else {
self.window.frame = CGRectMake(0, self.callViewHeight - 20.0f, self.window.bounds.size.width, self.window.bounds.size.height - self.callViewHeight + 20.0f);
}
} else {
self.window.frame = CGRectMake(0, self.callViewHeight - 20.0f, self.window.bounds.size.width, self.window.bounds.size.height - self.callViewHeight + 20.0f);
}
}];
}
-(void)hideVideoCallButton{
[UIView animateWithDuration:0.25
animations:^{
self.textWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
self.buttonWindow.transform = CGAffineTransformMakeTranslation(0, -self.callViewHeight);
self.window.frame = [UIScreen mainScreen].bounds;
} completion:^(BOOL finished) {
dispatch_async(dispatch_get_main_queue(), ^{
self.buttonWindow.hidden = TRUE;
self.buttonWindow = nil;
self.textWindow.hidden = TRUE;
self.textWindow = nil;
});
}];
}
-(void)buttonTouched{
NSLog(#"Button Touched");
}
#end
I tried in singleViewcontroller and UITabbar Controller also, the sample project I attached here, for status bar Tap action I followed Flar answer
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
[self createDummyView];
});
}
-(void)createDummyView{
if (_navigationBarTopView == nil) {
float statusBarHeight = [self statusBarHeight];
CGFloat width = [UIScreen mainScreen].bounds.size.width;
_navigationBarTopView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, self.navigationController.navigationBar.frame.size.height + statusBarHeight)];
[_navigationBarTopView setBackgroundColor:[UIColor colorWithRed:76.0/255.0 green:217.0/255.0 blue:100.0/255.0 alpha:1]];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, _navigationBarTopView.frame.size.height - 15,width, 10)];
[label setText:#"Touch to return to call"];
[label setTextColor:[UIColor whiteColor]];
[label setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleFootnote]];
[label setTextAlignment:NSTextAlignmentCenter];
[label setUserInteractionEnabled:YES];
[_navigationBarTopView addSubview:label];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[_navigationBarTopView addGestureRecognizer:singleFingerTap];
[self.navigationController.view addSubview:_navigationBarTopView];
}
-(float) statusBarHeight
{
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
return MIN(statusBarSize.width, statusBarSize.height);
}
-(void)handleSingleTap:(UITapGestureRecognizer*)recognizer{
NSLog(#"recognizer == %#", recognizer.view.tag);
}
I've added a subview to my table view controller. The subview has three subviews (a close button, a toolbar used to blur the main view, and a table view). The problem is that you are still able to see a bit of the main view at the bottom of the subview. I have tried initializing the subview with this frame, contentView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];, and that fixes the issue, but then if I scroll down on the parent view's table view, the subview can't be seen. How can I fix this?
- (void)showMenu
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
UIColor *kfbBlue = [UIColor colorWithRed:8.0/255.0f green:77.0/255.0f blue:139.0/255.0f alpha:1];
contentView = [[UIView alloc]initWithFrame:self.tableView.bounds];
contentView.autoresizesSubviews = YES;
contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
contentView.backgroundColor = [UIColor clearColor];
UIButton *closeMenuButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeMenuButton setFrame:CGRectMake(275, 10, 40, 40)];
[closeMenuButton setImage:[UIImage imageNamed:#"close"] forState:UIControlStateNormal];
[closeMenuButton addTarget:self action:#selector(closeMenu) forControlEvents:UIControlEventTouchUpInside];
blurredView = [[UIToolbar alloc]initWithFrame:contentView.bounds];
[blurredView setBarStyle:UIBarStyleBlack];
[blurredView setBarTintColor:kfbBlue];
MenuTableViewController *menu = [[MenuTableViewController alloc]initWithNibName:#"MenuTableViewController" bundle:nil];
menu.view.frame = CGRectMake(0, 30, screenWidth, screenHeight);
[self.view addSubview:contentView];
[contentView addSubview:blurredView];
[self addChildViewController:menu];
[contentView addSubview:menu.view];
[contentView addSubview:closeMenuButton];
self.navigationController.navigationBarHidden = YES;
self.tableView.scrollEnabled = NO;
}
I am displaying a new UIWindow and I'm wanting it to slide in from the left and slide into the left side when it's dismissed. How can I animate the showing and removing of a UIWindow?
This is how I'm currently showing my new UIWindow.
- (void)showMenu
{
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
UIButton *closeMenuButton = [UIButton buttonWithType:UIButtonTypeCustom];
[closeMenuButton setFrame:CGRectMake(250, 10, 50, 50)];
[closeMenuButton setImage:[UIImage imageNamed:#"close"] forState:UIControlStateNormal];
[closeMenuButton addTarget:self action:#selector(closeMenu) forControlEvents:UIControlEventTouchUpInside];
blurredView = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight)];
[blurredView setBarStyle:UIBarStyleBlack];
MenuTableViewController *menu = [[MenuTableViewController alloc]initWithNibName:#"MenuTableViewController" bundle:nil];
menu.view.frame = CGRectMake(0, 30, screenWidth, screenHeight - 50);
menuWindow = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
menuWindow.backgroundColor = [UIColor clearColor];
menuWindow.windowLevel = UIWindowLevelStatusBar;
menuWindow.rootViewController = menu;
[menuWindow addSubview:blurredView];
[blurredView addSubview:closeMenuButton];
[blurredView addSubview:menu.view];
[menuWindow makeKeyAndVisible];
}
Maybe Like this?
menuWindow = [[UIWindow alloc]initWithFrame:CGRectMake(0, 0, 0, screenHeight)];
menuWindow.backgroundColor = [UIColor clearColor];
menuWindow.windowLevel = UIWindowLevelStatusBar;
menuWindow.rootViewController = menu;
[menuWindow addSubview:blurredView];
[blurredView addSubview:closeMenuButton];
[blurredView addSubview:menu.view];
[menuWindow makeKeyAndVisible];
[UIView animateWithDuration:0.5 animations:^{
menuWindow.frame = screenRect;
blurredView.frame = screenRect;
menu.view.frame = CGRectMake(0, 30, screenWidth, screenHeight - 50);
}
completion:^(BOOL finished) {
}];
You can animate a UIWindow like any other view (using UIView animation methods).
A few things to remember. You need to retain a window for it to stay on screen. Also, you need to remember that windows live in screen coordinates, not in view coordinates, so you need to take into consideration the current interface orientation before starting an animation.
In the example above, I see you are creating a window, making it key and visible ... and nada. You need to retain the window.
Also, you are using the API incorrectly. Once you set a root view controller, the framework is responsible for the view. You add it as a subview again, and that can mess things. You really shouldn't add subviews to a window directly, just add them to the view controller's view hierarchy, and let that handle it.
I am interested in creating a pop-up notification view similar to the design patterns seen below, where a UIView pops up and the rest of the screen is darkened, and done without using a new modal view. Since this design pattern is so commonly seen, I was wondering if there is a "tried-and-true" way to doing it (or there a widely used open source framework like AFNetworking for downloading/uploading files and images)?
Thanks.
Here's a good start:
PopupView.h
#import <UIKit/UIKit.h>
#interface PopupView : NSObject
+ (void)addSubview:(UIView *)view;
+ (void)show;
+ (void)hide;
#end
PopupView.m:
#import "PopupView.h"
#implementation PopupView
+(UIView *)sharedView {
static UIView *_view = nil;
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
_view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)];
_view.backgroundColor = [UIColor blackColor];
_view.alpha = 0.6;
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hide)];
[_view addGestureRecognizer:singleFingerTap];
});
return _view;
}
+ (void)addSubview:(UIView *)view {
UIView *v = [PopupView sharedView];
[v addSubview:view];
}
+ (void)show {
UIView *v = [PopupView sharedView];
v.frame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height);
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
[[appDelegate window] addSubview:v];
}
+ (void)hide {
UIView *v = [PopupView sharedView];
[v removeFromSuperview];
[v.subviews makeObjectsPerformSelector: #selector(removeFromSuperview)];
}
Usage:
UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(50, 50, 200, 21)];
l.text = #"Hello";
l.textColor = [UIColor whiteColor];
[PopupView addSubview:l];
[PopupView show];
Or course instead of a label you can put any view(s) you want.
So this brings up an image that is slightly transparent with an "X" button in the top right hand corner that dismisses the image. For some reason it's not working! Any ideas on how to dismiss the image?
Check the button maybe I didn't create the selector correctly...
#define OVERLAY_TAG 997
-(void)showTutorial
{
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *overlay = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
overlay.backgroundColor = [UIColor clearColor];
overlay.userInteractionEnabled = YES;
[keyWindow addSubview:overlay];
UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(dismissTutorial)];
CGFloat border = 10;
CGRect frame = overlay.bounds;
// 20 is the status bar height (sorry for using the number)
frame = CGRectMake(border, border + 20, frame.size.width - border * 2, frame.size.height - border * 2 - 20);
// the black view in the example is probably a scroll view
UIView *blackView = [[UIView alloc] initWithFrame:frame];
blackView.backgroundColor = [UIColor blackColor];
blackView.alpha = 0.7;
[overlay addSubview:blackView];
// add all the subviews for your tutorial
/*UIImage* image = [UIImage imageNamed:#"slide_image_3.png"];
UIImageView* info = [[UIImageView alloc] initWithImage:image];
info.frame = CGRectMake(0, 0, 200, 150);
[blackView addSubview:info];*/
UIImage* image4 = [UIImage imageNamed:#"close_img.png"];
dismissTut = [[UIButton alloc] initWithFrame:CGRectMake(250, 18, 26, 26)];
[dismissTut setBackgroundImage:image4 forState:UIControlStateNormal];
[dismissTut addTarget:self action:#selector(dismissTutorial)
forControlEvents:UIControlEventTouchUpInside];
[dismissTut setShowsTouchWhenHighlighted:YES];
[blackView addSubview:dismissTut];
// make it appear with an animation
[UIView animateWithDuration:0.3
animations:^{blackView.alpha = 0.6;}
completion:^(BOOL finished){[overlay addGestureRecognizer:tapRecognizer];}];
}
-(void)dismissTutorial
{
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *overlay = [keyWindow viewWithTag:OVERLAY_TAG];
[UIView animateWithDuration:0.3
animations:^{
overlay.alpha = 0.0;
}
completion:^(BOOL finished){
[overlay removeFromSuperview];
}];
}
Add a tag to your view : overlay.tag = OVERLAY_TAG;
-(void)showTutorial
{
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
UIView *overlay = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
overlay.tag = OVERLAY_TAG;
.....
}