getting the statusBarFrame doesn't appear to return the correct value in iOS 11. I realize there may be a nicer way of dealing with this in the future using the Safe Area but right now I really need to get the statusBarFrame to work as it did before iOS 11. Here's how I usually get it.
UIApplication.shared.statusBarFrame
I'v verified that my app works properly before iOS 11. But in iOS 11 it appears to be backwards; for example, for an iPhone in portrait it should 20 and in landscape 0. But it returns 0 in portrait and 20 in landscape.
I've read all the posts regarding status bar issues and none address this problem.
I think it appears to be a timing issue. I wrapped the code that uses the statusBarFrame in a DispatchQueue.main.async {} closure and it works fine. I would consider this more of a bandaid. Still hoping for a proper solution.
Suggestions appreciated.
Thanks!
You can set background color for status bar during application launch or during viewDidLoad of your view controller. Here it works for me, in following ways.
extension UIApplication {
var statusBarView: UIView? {
return value(forKey: "statusBar") as? UIView
}
}
// Set upon application launch, if you've application based status bar
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UIApplication.shared.statusBarView?.backgroundColor = UIColor.red
return true
}
}
or
// Set it from your view controller if you've view controller based statusbar
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
UIApplication.shared.statusBarView?.backgroundColor = UIColor.red
}
}
Here is result:
Related
I want to keep support for both landscape and portrait orientation in General - > iphone orientation. However, when the app runs, I am making a start up call and based on a flag in the response , I want to disable landscape orientation or keep it throughout the app.
How can I programatically enable or disable landscape orientation?
In your view controller try overriding these properties like below:
override public var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
You may refer this apple documentation
As the requirement is to lock the application orientation based on the api response you can programatically handle it in the application delegate method
optional func application(
_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
XCode: 14
iOS: 16 (supports upto ios12)
i am writing ios sdk, which presents some UI when we call its method. but since its an SDK, i don't have access of client app delegate.
Goal: there are 2 screens (A) and (B). if screen(A) is on let say portrait mode, and user go to screen(B) from screen(A) then even if user rotate device to any other orientation, it should not rotate screen(B).
SDK supports min version ios 12 to 16+.
tried a few methods but none of them worked.
that's why posted a question here.
Shouldautoroate(),
Preferred Orientation () doesn't work.
override func viewDidLoad() {
super.viewDidLoad()
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
}
override open var shouldAutorotate: Bool {
return false
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .portrait
}
tried above approach but doesn't work.
shows erorr
BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:)
Update 1
i am able to implement orientation lock on screen, but its like, it will rotate it for a second, and figure out if it matches or supported orientation or not, if it doesn't match then it will rotate to require orientation.
but all of this takes 1-2 seconds, but i want to lock is completely, in sense that it should not even rotate for a second.
Update 2
i am able to implement lock orientation feature in iOS SDK. but that requires an additinal call. i am not sure if its a best way.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
// here .all - indicates current client app supports all orientations.
return <SDKClassName>.supportedInterfaceOrientations(.all)
}
supportedInterfaceOrientations() method check if current top viewcontroller is of kind SDKViewController and also checks for current interface orientation and update it to either landscape or portrait depending upon value, if top view controller is not SDKViewController then it returns the original supported interface mask value.
looking for a better solution now.
Thanks.
If you want to present different UIs for different orientations, for what I understood. The best API IMO is:
https://developer.apple.com/documentation/uikit/uiwindowscene/3198088-interfaceorientation
Import UIKit // guess is necessary
// inside your function or class check
UIWindowScene.interfaceOrientation (...)
//Then you have three options to check your environment
// Getting the interface attributes
var traitCollection: UITraitCollection
// The traits that describe the current environment of the scene.
var coordinateSpace: UICoordinateSpace
// The coordinate space occupied by the scene.
var sizeRestrictions: UISceneSizeRestrictions?
from those you can create one UI or another.
I think I had the same issue in the past and the problem was ViewController was put into NavigationController.
If so - subclass NavigationController, override same methods that you did in ViewController B, and use it for wrapping ViewController B
class CustomNavigationController: NavigationController {
override open var shouldAutorotate: Bool {
return false
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .portrait
}
}
This question already has an answer here:
How to set color of status bar showing carrier, time, and battery on top
(1 answer)
Closed 3 years ago.
When I scroll down Status bar across my text, and its seems terribly
Can I make a status bar background grey or dark and text of status bar light?
The style of the status bar can be changed to a status bar with white content. Go to the ViewController.swift file and add the following lines of code.
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
enum UIStatusBarStyle : Int
case default : A dark status bar, intended for use on light
backgrounds.
case lightContent : A light status bar, intended for use on dark
backgrounds.
case darkContent : A dark status bar, intended for use on light
backgrounds.
If you want to change the background color of the status bar together, you can do the following:
if #available(iOS 13.0, *) {
let statusBarView = UIView(frame: view.window?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
statusBarView.backgroundColor = backgroundColor
view.addSubview(statusBarView)
} else {
// Fallback on earlier versions
let statusBarView = UIView(frame: UIApplication.shared.statusBarFrame)
statusBarView.backgroundColor = backgroundColor
view.addSubview(statusBarView)
}
add in your appDelegate this code
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UINavigationBar.appearance().barStyle = .blackOpaque
return true
}
or in your info plist use
or in specific view
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
navigationController?.navigationBar.barStyle = .blackOpaque
}
for view controller
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
When running a simple proof-of-concept iPhone app on my phone (iOS 13.1.2), it doesn't rotate upside down. It will rotate to either of the landscape orientations just fine, but not upside down. One strange thing is that there's also a UITextEffects window whose view controllers get supportedInterfaceOrientations called on them (and they return .allButUpsideDown, which matches with the observed behavior). The project is here, but I'll show all of the code inline.
AppDelegate.swift:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return .all
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let c = ViewController()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = c
window?.makeKeyAndVisible()
return true
}
}
ViewController.swift:
import UIKit
class ViewController: UIViewController {
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .all
}
override var shouldAutorotate: Bool {
return true
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .purple
let redView = UIView()
redView.backgroundColor = .red
redView.frame = CGRect(x: 20, y: 20, width: 100, height: 100)
view.addSubview(redView)
}
}
Info.plist (excerpt):
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
This is on purpose, the newer iPhones without Touch Id doesn't have the Upside Down capability. If you run your example on iPhone 8, it rotates as it should.
In https://forums.developer.apple.com/message/268015, an Apple staffer says:
"It is by design. We're getting documentation updated in a future release to reflect that."
And the official Apple documentation says:
The system intersects the view controller's supported orientations with the app's supported orientations (as determined by the Info.plist file or the app delegate's application:supportedInterfaceOrientationsForWindow: method) and the device's supported orientations to determine whether to rotate. For example, the UIInterfaceOrientationPortraitUpsideDown orientation is not supported on iPhone X.
Also, see the Apple Visual Design Orientation:
An app that runs only in portrait mode should rotate its content 180 degrees when the user rotates the device 180 degrees—except on iPhone X, which doesn’t support upside-down portrait mode.
I'm trying to get the updated status bar frame height using didChangeStatusBarFrame, but…
The new/updated frame isn't up-to-date and sometimes returns the old and sometimes the new (correct) height.
func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
print(UIApplication.shared.statusBarFrame.height) // Sometimes wrong
}
My current workaround is to use DispatchQueue.main.async:
func application(_ application: UIApplication, didChangeStatusBarFrame oldStatusBarFrame: CGRect) {
DispatchQueue.main.async {
print(UIApplication.shared.statusBarFrame.height) // So far correct in all my tests
}
}
I guess it's because some layout is happening in the background and the statusBarFrame needs to update first.
What's the real reason and is there a better, not-so-hacky way to wait for the correct status bar frame height?