How to get statusbarView in iOS16 - ios16

I use the following method to display the picture of the status bar, but this vulnerability already exists in iOS16. Is there a way to display other bars?
UIView *statusBarView = nil;
if (#available(iOS 13.0, *)) {
UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;
CGRect frame = statusBarManager.statusBarFrame;
if ([statusBarManager respondsToSelector:#selector(createLocalStatusBar)]) {
UIView *_localStatusBar = [statusBarManager performSelector:#selector(createLocalStatusBar)];
[self imageFromView:_localStatusBar];
if ([_localStatusBar respondsToSelector:#selector(statusBar)]) {
statusBarView = [_localStatusBar performSelector:#selector(statusBar)];
}
}
} else {
UIWindow *statusBarWindow = [[UIApplication sharedApplication] valueForKey:#"statusBarWindow"];
if (statusBarWindow) {
statusBarView = [[UIApplication sharedApplication] valueForKey:#"statusBar"];
}
}

Related

How to detect the double tap and hold gesture when accessibility is on?

I have an app that displays a link when you scan a QR code.
With accessibility turned on (VoiceOver):
When I double click on the link I open a custom alert.
The problem is that when I double-click and hold on the link I still get the alert instead of the context menu.
My code:
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction {
BOOL linkScheme = ([URL.scheme isEqualToString: #"http"] || [URL.scheme isEqualToString: #"https"]);
if ([[UIApplication sharedApplication] canOpenURL:URL]){
NSUserDefaults *saveURL = [NSUserDefaults standardUserDefaults];
[saveURL setObject:URL.absoluteString forKey:#"SavedURL"];
[saveURL synchronize];
if (linkScheme) {
// if (detect double click and hold) {
return YES;
} else {
if(!GUIManager.instance.isAlwaysAskChecked){
if(GUIManager.instance.openInThisAppButtonChecked) {
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
WebViewController* webView = [[WebViewController alloc] init];
[topController showViewController:webView sender:nil];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:URL.absoluteString]];
}
} else {
tableV.accessibilityElementsHidden = YES;
AlertView* alertView = [[AlertView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.view addSubview: alertView];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, alertView);
}
return NO;
}
}
}
return YES;
}
I'd like to enable the context menu on double-click and hold (with accessibility (VoiceOver) enabled), instead of displaying an alert.

How to add the view to whole screen

I have an 2 vc,with push from one screen to another screen.In my vc2 programmatically i am adding the nav bar title, bar button . But when i add the view some 10 points from top is reduced. not showing fully. I tried all the possibilities. Attached the image also:
in my vc2 :
- (void)viewDidLoad {
[super viewDidLoad];
_menuView.hidden = YES;
[self navItems];
}
-(void)navItems{
UIImage* filterImage = [UIImage imageNamed:#"filter.png"];
CGRect frameimg = CGRectMake(0,0, 15,15);
filterBtn = [[UIButton alloc] initWithFrame:frameimg];
[filterBtn setBackgroundImage:filterImage forState:UIControlStateNormal];
[filterBtn addTarget:self action:#selector(MenuTap:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *filter =[[UIBarButtonItem alloc] initWithCustomView:filterBtn];
self.navigationItem.rightBarButtonItem = filter;
self.title = #"Demo";
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"" style:UIBarButtonItemStylePlain target:nil action:nil];
}
- (IBAction)MenuTap:(id)sender
{
_menuView.hidden = NO;
//1
// [self.navigationController.view addSubview:_menuView];
// [self.view addSubview:_menuView];
//2
// UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
// [window addSubview: _menuView];
//
//3
// UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
//[currentWindow addSubview:_menuView];
//4
//[[UIApplication sharedApplication].windows.lastObject addSubview:_menuView];
//5
// self.navigationController.navigationBar.layer.zPosition = -1;
//[self.view addSubview:_menuView];
}
But not able to show fully any idea please ?
based on your question in here added the detail answer, if you want to show below the status bar , then you need to get the status bar height initially, there after you need to add the y position how much you need.
- (IBAction)MenuTap:(id)sender
{
_menuView.hidden = NO;
//initially getStatusbar height
float statusBarHeight = [self statusBarHeight];
// assign your subview to window bounds
_menuView.frame = [[UIScreen mainScreen] bounds];
CGRect frameRect = _menuView.frame;
// convert your y- coordinates based on your need
frameRect.origin.y = statusBarHeight;
_menuView.frame = frameRect;
[self.navigationController.view addSubview:_menuView];
}
-(float) statusBarHeight
{
CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
return MIN(statusBarSize.width, statusBarSize.height);
}
I am updating with #Anbu.Karthic solution.
In your (IBAction)MenuTap:(id)sender update the code with below. It will work. I have tried.
- (IBAction)MenuTap:(id)sender
{
_menuView.hidden = NO;
[self.navigationController.view addSubview:_menuView];
_menuView.frame = [[UIScreen mainScreen] bounds];
}

iOS [Obj-C] - NavigationBar transparent with visible items while scrolling

This is my question
CONTEXT
I have a ViewController which I have an effect where the Navigation Bar gets transparent when the user go down in the scroll, and the Navigation Bar gets normal when the user go up in scroll view. This effect I did with the UIScrollViewDelegate's methods. This is the code:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat offset = scrollView.contentOffset.y;
if (scrollView.contentOffset.y < 0){
scrollView.bounces = false;
}else{
scrollView.bounces = true;
}
CGFloat currentAlpha = (offset / 310);
if (currentAlpha < 0) {
self.navigationController.navigationBar.translucent = YES;
self.navigationController.navigationBar.alpha = 1;
self.navigationController.titleNavBar.alpha = 0; //This property I made in an UINavigationController extension
} else {
self.navigationController.navigationBar.translucent = YES;
self.navigationController.navigationBar.alpha = 1;
self.navigationController.titleNavBar.alpha = currentAlpha; //This property I made in an UINavigationController extension
[self.navigationController.navigationBar setBackgroundColor:[UIColor colorWithRed:0.0f/0.0f green:136.0f/255.0 blue:206.00f/255.0f alpha:currentAlpha]];
}
}
With the previous code I got the effect, but I have a problem: I can't add it to the status bar because self.navigationController.navigationBar.translucent is set on YES. So, in the iPhones, the status bar shows transparent and in the iPhone X shows bigger this transparence than another iPhones (see the image).
Anyone know how can I do this transparent effect with Navigation Bar and the Statsus Bar?
You need to change statusBar UIView color with NavigationBar color.
Create AppDelegate SharedInastance :
+ (AppDelegate *)sharedAppDelegate {
return (AppDelegate *)[UIApplication sharedApplication].delegate;
}
Add below code in AppDelegate to get status bar view:
- (UIView *)statusBarView {
return [[[UIApplication sharedApplication] valueForKey:#"statusBarWindow"] valueForKey:#"statusBar"];
}
Add below code when you want to change status bar color:
[[AppDelegate sharedAppDelegate] statusBarView].backgroundColor = [UIColor redColor];

Show splash screen each time app becomes active

I want the splash screen to be displayed each time app becomes active. I have created a function showSplash which I call in applicationDidBecomeActive:
-(void)showSplash
{
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"Default.png"]];
[self.window.rootViewController.view addSubview: splashScreen];
[self.window makeKeyAndVisible];
NSLog(#"begin splash");
[UIView animateWithDuration: 4.2
delay: 0.5
options: UIViewAnimationOptionCurveEaseOut
animations: ^{
splashScreen.alpha = 0.0;
}
completion: ^ (BOOL finished) {
[splashScreen removeFromSuperview];
NSLog(#"end splash");
}
];
}
This is how I call this function :
- (void)applicationDidBecomeActive:(UIApplication *)application {
[self showSplash];
}
But no splash screen appears. Please correct me.
If you want the application to have a fresh start every time you get back to it, you could also disable background execution, as stated in the Apple Documentation (last section titled "Opting Out of Background Execution"):
If you do not want your app to run in the background at all, you can
explicitly opt out of background by adding the
UIApplicationExitsOnSuspend key (with the value YES) to your app’s
Info.plist file.
after adding the splash view - bring it to front
change
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"Default.png"]];
[self.window.rootViewController.view addSubview: splashScreen];
[self.window makeKeyAndVisible];
to
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"Default.png"]];
[self.window addSubview: splashScreen];
[self.window bringSubviewToFront: splashScreen]; //!
[self.window makeKeyAndVisible];
Please, ensure your window root view controller main view is the top most view in your App in the moment you want to show splash...
Check frame of splashScreen (UIImageView). Set its frame to bounds of your root view controller.
You can try to hunt the top view controller with a recursion like this:
- (UIViewController *)findTopViewController {
return [self topViewControllerFrom:self.window.rootViewController];
}
- (UIViewController *)topViewControllerFrom:(UIViewController *)vc {
if (vc.navigationController.visibleViewController != nil) {
return [self topViewControllerFrom:vc.navigationController.visibleViewController];
}
if (vc.tabBarController.selectedViewController != nil) {
return [self topViewControllerFrom:vc.tabBarController.selectedViewController];
}
return vc;
}
Now calling [self findTopViewController] should hopefully return the currently visible/top VC of your app, and you can do:
[[self findTopViewController].view addSubview:splashScreen];
...
you can do something like:
#import "AppDelegate.h"
#define kSplashScreen (UIScreen.mainScreen.bounds.size.height == 568) ? #"Default-568h" \
: (UIScreen.mainScreen.bounds.size.height == 667) ? #"Default-667" \
: (UIScreen.mainScreen.bounds.size.height == 736) ? #"Default-Portrait" \
: #"Default"
#interface AppDelegate ()
#property (nonatomic) UIWindow *splashWindow;
#property (nonatomic) UIWindow *keyWindow;
#property (nonatomic, getter=isSplashConfigured) BOOL splashConfigured;
#property (nonatomic, getter=isShowingSplash) BOOL showingSplash;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self animateSplash];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self showOrHideSplash];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self showOrHideSplash];
}
- (void)showOrHideSplash
{
[self.splashWindow setHidden:[self isShowingSplash]];
if ([self isShowingSplash])
{
[self.keyWindow makeKeyAndVisible];
}
else
{
[self.splashWindow makeKeyAndVisible];
[self animateSplash];
}
self.showingSplash = !self.showingSplash;
}
- (void)animateSplash
{
if ([self isSplashConfigured])
{
[self.window.rootViewController.view addSubview:self.splashWindow];
[self.window makeKeyAndVisible];
}
else
{
self.keyWindow = [[UIApplication sharedApplication] keyWindow];
self.splashWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.splashWindow.rootViewController = [[UIViewController alloc] init];
self.splashWindow.rootViewController.view.frame = self.splashWindow.bounds;
UIImageView *splashImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:kSplashScreen]];
splashImage.frame = self.splashWindow.bounds;
[self.splashWindow.rootViewController.view addSubview:splashImage];
[self.splashWindow makeKeyAndVisible];
[self.splashWindow setHidden:YES];
self.splashConfigured = YES;
}
NSLog(#"begin splash");
__weak AppDelegate* weakSelf = self;
[UIView animateWithDuration:4.2 delay:0.5 options:UIViewAnimationOptionCurveEaseOut animations: ^{
weakSelf.splashWindow.alpha = 1.0;
weakSelf.splashWindow.alpha = 0.0;
} completion: ^(BOOL finished) {
[weakSelf.splashWindow removeFromSuperview];
NSLog(#"end splash");
}];
}
#end
This is a bit cumbersome solution, but it works fine. The idea is add new UIWindow on top of all controllers
- (void)showSplash {
id <UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
UIWindow *window = [[UIWindow alloc] initWithFrame:[appDelegate window].frame];
UIViewController *splashController = [UIViewController new];
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default.png"]];
splashController.view = imgView;
window.rootViewController = splashController;
window.windowLevel = UIWindowLevelAlert;
window.hidden = NO;
[window makeKeyAndVisible];
[UIView animateWithDuration:4.2 delay:0.5 options:UIViewAnimationOptionCurveEaseOut animations:^{
window.alpha = 0.0;
} completion:^(BOOL finished) {
window.hidden = YES;
window.rootViewController = nil;
[[appDelegate window] makeKeyAndVisible];
[[appDelegate window] setNeedsDisplay];
}];
}
Please find below a solution for this problem.
Split the splash screen code into two methods; showSplash and hideSplash.
Call showSplash in the method applicationWillResignActive. In the method, create and add the imageView to rootViewController; set it's alpha to 0.0f and then animate it to alpha 1.0f. This is to make sure that the user doesn't see the imageView when the app is going to background.
Now call hideSplash in applicationDidBecomeActive. In hideSplash remove the imageView with animation. See the code below;
-(void)showSplash
{
_splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"Default"]];
[self.window.rootViewController.view addSubview:_splashScreen];
_splashScreen.alpha = 0.0f;
[UIView animateWithDuration:0.3f animations:^{
_splashScreen.alpha = 1.0f;
}];
}
- (void)hideSplash
{
[UIView animateWithDuration: 4.2
delay: 0.5
options: UIViewAnimationOptionCurveEaseOut
animations: ^{
_splashScreen.alpha = 0.0;
}
completion: ^ (BOOL finished) {
[_splashScreen removeFromSuperview];
NSLog(#"end splash");
}
];
}
- (void)applicationWillResignActive:(UIApplication *)application {
[self showSplash];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[self hideSplash];
}
I hope this helps! :-)
Add
splashScreen.frame = self.window.rootViewController.view.frame;
below
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"alertBg.png"]];
example
-(void)showSplash
{
UIImageView *splashScreen = [[UIImageView alloc] initWithImage:[UIImage imageNamed: #"Default.png"]];
splashScreen.frame = self.window.rootViewController.view.frame;
[self.window.rootViewController.view addSubview: splashScreen];
[self.window makeKeyAndVisible];
NSLog(#"begin splash");
[UIView animateWithDuration: 4.2
delay: 0.5
options: UIViewAnimationOptionCurveEaseOut
animations: ^{
splashScreen.alpha = 0.0;
}
completion: ^ (BOOL finished) {
[splashScreen removeFromSuperview];
NSLog(#"end splash");
}
];
}
The best way to achieve this is to add the image in AppDelegate's window.
In the below code statusView is one of the view, which consist of some image. So add it to your AppDelegate's window as a subView
[[[[UIApplication sharedApplication] delegate] window] addSubview:statusView];
Now whenever you want it to appear for some amount of time, you show this view, but same time bring it to front.
-(void)showStatusView{
[UIView animateWithDuration:0.5 animations:^{
[[[[UIApplication sharedApplication] delegate] window] bringSubviewToFront:statusView];
statusView.alpha = 1;
}];
}
Better Call the above method on the AppDelegate's method didBecomeActive.
Also, show the splash screen as soon as application is going to resign active. This way, iOS will take the snapshot of the screen, which will be shown for fraction of seconds when the app is about to become active.
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self showStatusView];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[self showStatusView];
}
Once the app is active, you can show the actual splash screen for some duration & then your usual app state.
First create your launch screen or image in didFinishLaunchingWithOptions function.
After this write your code like this-
Root view controller is not always the presented view controller. This can cause your splash screen to be hidden under bunch of other view controllers. Try using something like (swift syntex):
func getTopViewController() -> UIViewController?{
if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController{
while ((topController.presentedViewController) != nil) {
topController = topController.presentedViewController!
}
return topController
}
return nil
}
And add your splash view to the top view controller
launch your application normally every-time, call your method in applicationBecomeActive, and add you image view on Appdelegate.window and remove it after some time by timer.
[self.window addSubview: splashScreen];
You should use the following line:
[self.window addSubview: splashScreen];
instead of
[self.window.rootViewController.view addSubview: splashScreen];
You can reuse your launchScreen to show up instead of showing imageview. This comes handdy when you have complex launchscreen instead of single image as a splash screen.
func applicationWillResignActive(_ application: UIApplication) {
guard let window = UIApplication.shared.windows.last,
let launchScreen = UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController(),
let launchView = launchScreen.view else {return}
launchView.tag = 8888
launchView.frame = window.bounds
launchView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
window.addSubview(launchView)
window.makeKeyAndVisible()
}
func applicationDidBecomeActive(_ application: UIApplication) {
guard let window = UIApplication.shared.windows.last,
let view = window.viewWithTag(8888) else {return}
view.removeFromSuperview()
}

iOS 7 UISearchBarDisplayController overlapping search bar and misplacing navigation controller

I have found a lot of solutions to avoid this problem, sadly none of them has worked for me.
Here is the screenshot of the issue when I click the searchBar.It pushes up the navigation controller also as you can see.
Now here is what I have tried.
Solution 1:
if([self respondsToSelector:#selector(setEdgesForExtendedLayout:)])
{
self.edgesForExtendedLayout = UIRectEdgeNone;
}
Sloution 2:
-(void)viewDidAppear:(BOOL)animated{
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
[self.cityTableView setFrame:CGRectMake(self.cityTableView.frame.origin.x, self.cityTableView.frame.origin.y+statusBarFrame.size.height, self.cityTableView.frame.size.width, self.cityTableView.frame.size.height)];
}
}
Solution 3:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
if (IS_OS_7_OR_LATER) {
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect frame = self.citySearchBar.frame;
frame.origin.y += statusBarFrame.size.height;
self.citySearchBar.frame = frame;
}
}
- (void)searchDisplayControllerWillEndSearch:(UISearchDisplayController *)controller {
if (IS_OS_7_OR_LATER) {
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect frame = self.citySearchBar.frame;
frame.origin.y -= statusBarFrame.size.height;
self.citySearchBar.frame = frame;
}
}
Solution 4:
- (void)searchDisplayControllerWillBeginSearch:(UISearchDisplayController *)controller {
self.navigationController.navigationBar.translucent = YES;
}
- (void)searchDisplayControllerDidEndSearch:(UISearchDisplayController *)controller {
self.navigationController.navigationBar.translucent = NO;
}
Solution 5: May be useful in case of Autolayout.But I am not using it.
- (void) viewDidLayoutSubviews
{
if(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
{
CGRect viewBounds = self.view.bounds;
CGFloat topBarOffset = self.topLayoutGuide.length;
viewBounds.origin.y = topBarOffset * -1;
self.view.bounds = viewBounds;
}
}
So what am I missing here?

Resources