I used UINavigationBar and when I change to landscape mode the bar look like this .
in portrait mode
Try this way and this code for navigation bar not navigation controller . may be you missing to set Constraint or conflict each other
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator){
super.viewWillTransition(to: size, with: coordinator)
var frame: CGRect = (self.navigationController?.navigationBar.frame)!
coordinator.animate(alongsideTransition: { (UIViewControllerTransitionCoordinatorContext) -> Void in
let orient = UIApplication.shared.statusBarOrientation
switch orient {
case .portrait:
frame.size.height = 44
frame.size.width = self.view.frame.width
default:
frame.size.height = 32
frame.size.width = self.view.frame.width
}
}, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
print("rotation completed")
self.navigationController?.navigationBar.frame = frame
})
}
Related
Using iOS14.1, Swift5.3,
I try to rotate my iPad from portrait to landscape. However, the view is black on one side in landscape mode (see video).
What do I need to do in order to rotate an iPad ?
open override var shouldAutorotate: Bool {
return true
}
open override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (context) in
guard let windowInterfaceOrientation = self.windowInterfaceOrientation else { return }
if windowInterfaceOrientation.isLandscape {
// activate landscape changes
print("landscape now")
print(UIScreen.main.bounds.height)
print(UIScreen.main.bounds.width)
self.view.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.view.setNeedsLayout()
self.view.layoutSubviews()
} else {
// activate portrait changes
print("portrait now")
print(UIScreen.main.bounds.height)
print(UIScreen.main.bounds.width)
self.view.frame = CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
self.view.setNeedsLayout()
self.view.layoutSubviews()
}
})
}
private var windowInterfaceOrientation: UIInterfaceOrientation? {
if #available(iOS 13.0, *) {
return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
} else {
return UIApplication.shared.statusBarOrientation
}
}
I have a pop over and I am trying to change the width when the orientation changes. I get the width that I want when the popUp shows in the current orientation, but when I switch from .portrait -> .landscape I don't get the width that I want.It keeps the .portrait once for example.
I read the documentation about the popoverPresentationController(_:willRepositionPopoverTo:in:)
but I can't figure out how it works.
actually it doesn't even called when I change the orientation. The rest of the UIPopoverPresentationControllerDelegate that I use they work correctly.
Is this the correct one for changing the size of the PopUp , or should I use something else ?
Any help? Thanks a lot
func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) {
if popoverPresentationController.presentingViewController is PopUpTextPickerViewController{
let viewFrame = popoverPresentationController.presentingViewController.view.frame
let newRect = CGRect(x: viewFrame.origin.x, y: viewFrame.origin.y, width: self.view.bounds.width, height: 100)
let newView = UIView(frame: newRect)
rect.pointee = newRect
view.pointee = newView
}
print("popoverPresentation:willRepositionPopOverTo")
}
//Shows the PopUpTextPickerViewController on the screen
#IBAction func fontButtonPressed(_ sender: UIBarButtonItem) {
subscribeToNotifications(notification: .popUpTextPickerViewController)
let fontController = storyboard?.instantiateViewController(withIdentifier: "popUpTextPickerViewController") as! PopUpTextPickerViewController
fontController.fontName = self.fontName
fontController.fontSize = self.fontSize
fontController.modalPresentationStyle = UIModalPresentationStyle.popover
fontController.popoverPresentationController?.delegate = self
fontController.popoverPresentationController?.barButtonItem = fontButton
fontController.popoverPresentationController?.backgroundColor = .clear
fontController.popoverPresentationController?.sourceView = self.view
fontController.preferredContentSize = CGSize(width: self.view.bounds.width, height: 100)
present(fontController, animated: true, completion: nil)
}
Try implementing below code in your parent view controller. UIKit calls this method before changing the size of a presented view controller’s view -
override func viewWillTransition(to size: CGSize,
with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if let myVC = self.presentedViewController as? MyViewController {
myVC.preferredContentSize = CGSize(width: {yorWidth}, height: {yourHeight})
}
}
Update: I ended up by hiding the default navigation bar and added a UIView which looks same as the navigation bar. This may not sound good but instead of patching into the UINavigationBar this is good.
This is my custom UINavigationBar class which I have created to increase the height of navigation bar in my app. It doesn't work for me. Here's the code.
class PPBaseNavigationBar: UINavigationBar {
///The height you want your navigation bar to be of
static let navigationBarHeight: CGFloat = 83.0
///The difference between new height and default height
static let heightIncrease: CGFloat = navigationBarHeight - 44
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
private func initialize() {
let shift = PPBaseNavigationBar.heightIncrease/2.0
///Transform all view to shift upward for [shift] point
self.transform = CGAffineTransform(translationX: 0, y: -shift)
}
override func layoutSubviews() {
super.layoutSubviews()
let shift = PPBaseNavigationBar.heightIncrease/2.0
///Move the background down for [shift] point
var classNamesToReposition: Array<String>?
if #available(iOS 10.0, *) {
classNamesToReposition = ["_UIBarBackground"]
} else {
classNamesToReposition = ["_UINavigationBarBackground"]
}
for view: UIView in self.subviews {
if (classNamesToReposition?.contains(NSStringFromClass(view.classForCoder)))! {
let bounds: CGRect = self.bounds
var frame: CGRect = view.frame
frame.origin.y = bounds.origin.y + shift - 20.0
frame.size.height = bounds.size.height + 20.0
view.frame = frame
}
}
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
let amendedSize:CGSize = super.sizeThatFits(size)
let newSize:CGSize = CGSize.init(width: amendedSize.width, height: PPBaseNavigationBar.navigationBarHeight)
return newSize;
}
}
All the method gets called except override func sizeThatFits(_ size: CGSize) -> CGSize {...} not sure, why?
It is not permissible to change the navigation bar object or modify its bounds, frame, or alpha values directly.
Modifying the Navigation Bar Object Directly
You can use custom view as navigation bar. Customize view as per your requirement(e.g change height) and hide the default navigation bar as
self.navigationController?.setNavigationBarHidden(true, animated: false)
layoutSubviews works as well override func sizeThatFits(_ size: CGSize).
so do not worry if it is not sizeThatFits called. I checked in layoutSubviews Navigationbar height are changing.
for view: UIView in self.subviews {
if (classNamesToReposition?.contains(NSStringFromClass(view.classForCoder)))! {
let bounds: CGRect = self.bounds
var frame: CGRect = view.frame
frame.origin.y = bounds.origin.y + shift - 20.0
frame.size.height = bounds.size.height + 150.0
view.frame = frame
}
}
Try like this, this worked for me in Swift 3:
extension UINavigationBar {
override open func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: UIScreen.main.bounds.size.width, height: "Your custom height")
}
}
// MARK: - View life cycle methods
class DVNavigationController: UINavigationController {
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
navigationBar.frame.size.height = "Your custom height"
}
}
Finally assign this custom UINavigationController class to your navigationController.
Change your code like below
open override func sizeThatFits(_ size: CGSize) -> CGSize {
let amendedSize:CGSize = super.sizeThatFits(size)
let newSize:CGSize = CGSize.init(width: amendedSize.width, height: PPBaseNavigationBar.navigationBarHeight)
return newSize;
}
Might be worked for you.
I want to modify the height of popover in landscape mode, but it only work in portrait mode.
I want it's height equal to screenSize.height * 0.7, but it doesn't work with my code below.
Here is my code:
if let orientation = UIDevice.current.value(forKey: "orientation") as? Int {
let diamondViewController = DiamondViewController()
diamondViewController.mode = .buyDiamondPopup
diamondViewController.resetBackgroundColor = {
self.view.backgroundColor = .clear
}
let screenSize = UIScreen.main.bounds
if orientation == 3 { // LandscapeRight
diamondViewController.preferredContentSize = CGSize(width: screenSize.width * 0.6, height:
screenSize.height * 0.7)
} else {
diamondViewController.preferredContentSize = CGSize(width: screenSize.width - 60, height:
min(screenSize.height - 180, CGFloat(5 * 70 + 110) ))
}
diamondViewController.modalPresentationStyle = .popover
if let popover = diamondViewController.popoverPresentationController {
popover.permittedArrowDirections = .init(rawValue: 0)
popover.sourceView = self.view
popover.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
popover.delegate = self
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
self.present(diamondViewController, animated: true, completion: nil)
}
}
...
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Instead of this
diamondViewController.preferredContentSize = CGSize(width: screenSize.width * 0.6, height: screenSize.height * 0.7)
Try this below
diamondViewController.view = CGRect(x: diamondViewController.view.frame.origin.x ,y: diamondViewController.view.frame.origin.y ,width: screenSize.width * 0.6, height: screenSize.height * 0.7)
If it doesn't help then let me know.
Have you tried using the "Vary for traits" tool? It allows you to apply different constraints depending on the devices orientation. It can be found near the bottom right corner in storyboard next to the different constraint options.
I think you have to set landscape's height in a dispatched thread. Here is my suggestion.
if let orientation = UIDevice.current.value(forKey: "orientation") as? Int {
let diamondViewController = DiamondViewController()
diamondViewController.mode = .buyDiamondPopup
diamondViewController.resetBackgroundColor = {
self.view.backgroundColor = .clear
}
// HERE IS THE CHANGE: CALL FUNC TO GET SIZE
let size = diamondViewController.myPreferedContentSize(landscape: landscape)
diamondViewController.preferredContentSize = size
...
}
}
The func myPreferedContentSize is defined in 'diamondViewController' class as following:
func myPreferedConentSize(landcape: Bool) -> CGSize
{
let screenSize = UIScreen.main.bounds
let retSize: CGSize
if landscape { // LandscapeRight
retSize = CGSize(width: screenSize.width * 0.6, height:
screenSize.height * 0.7)
} else {
retSize = CGSize(width: screenSize.width - 60, height:
min(screenSize.height - 180, CGFloat(5 * 70 + 110) ))
}
return retSize
}
In your diamondViewController class, override this func and add codes:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
let landscape = size.width > size.height
DispatchQueue.main.async {
[weak self] in
guard let this = self else { return }
this.preferredContentSize = this.myPreferedConentSize(
landscape: landscape)
}
}
It is important to call func myPreferedConentSize in DispatchQueue.main.async thread. In this async main thread, it will ask your view controller to set preferred content size in either portrait or landscape orientation correctly.
I implemented custom navigation bar height, by subclassing it with following code
class TMNavigationBar: UINavigationBar {
///The height you want your navigation bar to be of
static let navigationBarHeight: CGFloat = 44.0
///The difference between new height and default height
static let heightIncrease:CGFloat = navigationBarHeight - 44
override init(frame: CGRect) {
super.init(frame: frame)
initialize()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initialize()
}
private func initialize() {
let shift = TMNavigationBar.heightIncrease/2
///Transform all view to shift upward for [shift] point
self.transform =
CGAffineTransformMakeTranslation(0, -shift)
}
override func layoutSubviews() {
super.layoutSubviews()
let shift = TMNavigationBar.heightIncrease/2
///Move the background down for [shift] point
let classNamesToReposition: [String] = ["_UINavigationBarBackground"]
for view: UIView in self.subviews {
if classNamesToReposition.contains(NSStringFromClass(view.dynamicType)) {
let bounds: CGRect = self.bounds
var frame: CGRect = view.frame
frame.origin.y = bounds.origin.y + shift - 20.0
frame.size.height = bounds.size.height + 20.0
view.frame = frame
}
}
}
override func sizeThatFits(size: CGSize) -> CGSize {
let amendedSize:CGSize = super.sizeThatFits(size)
let newSize:CGSize = CGSizeMake(amendedSize.width, TMNavigationBar.navigationBarHeight);
return newSize;
}
}
Following problem occurs only on iOS 10: (black space between bar & view)
No idea what's happening there. But in storyboard it's generated this warning, and there's no way to fix it in IB (warning only appears when i change subclass of navigation bar in IB).
Works on iOS 10, Swift 3.0:
extension UINavigationBar {
open override func sizeThatFits(_ size: CGSize) -> CGSize {
let screenRect = UIScreen.main.bounds
return CGSize(width: screenRect.size.width, height: 64)
}
}
I checked Interface debugger and this is what i see (so basically it's trying to change navigation bar height, bit it's stays same and it's showing just black space - which is window color):
With later investigation i noticed that it's not calling: "_UINavigationBarBackground"
Then i checked view.classForCoder from fast enumeration, and discovered that key is changed to "_UIBarBackground", so i updated layoutSubviews():
override func layoutSubviews() {
super.layoutSubviews()
let shift = TMNavigationBar.heightIncrease/2
///Move the background down for [shift] point
let classNamesToReposition = isIOS10 ? ["_UIBarBackground"] : ["_UINavigationBarBackground"]
for view: UIView in self.subviews {
if classNamesToReposition.contains(NSStringFromClass(view.classForCoder)) {
let bounds: CGRect = self.bounds
var frame: CGRect = view.frame
frame.origin.y = bounds.origin.y + shift - 20.0
frame.size.height = bounds.size.height + 20.0
view.frame = frame
}
}
}
Cheers.