popToRootViewController not working when preferLargeTitle is enabled in iOS 11 - swift

This code below is working when i'm not using preferLargeTitles. Is this a bug in iOS 11? Any ideas?
This is my code on applying largeTitles and i'm running iOS 11 in a rootViewController:
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
navigationController?.navigationBar.largeTitleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
}
And this is my code where I disable the preferLargeTitle in second stack of navigationController:
if #available(iOS 11.0, *) {
// Keep small title. If I uncomment this code, popToRootViewController will work. I just want to have a large title at the rootViewController.
navigationItem.largeTitleDisplayMode = .never
}
At the end of the navigation stack... I call this code below and it's not working.
_ = self.navigationController?.popToRootViewController(animated: true)
Please read code comments. Thanks!

I just figured out that this is not related with the iOS 11 issue. This is because I'm using another library for keyboard avoiding which is has an issue with iOS 11.

Related

Navigation Bar's content partially not visible in modal on iOS 13

A storyboard based application is having issue rendering the navigation bar's content when the navigation bar is displayed in a modal screen, but only when on a physical device. The code behaves properly in iOS 12 and in all simulators both iOS 12 and iOS 13.2.2.
On the left of the screenshot is a iPhone 11 simulator running iOS 13.2.2; on the right is a Reflector projection of my iPhone Xs running iOS 13.2.2 of the same code. We can see there's a space between the tableview and the navigation bar content on the physical device, but on the simulator the tableview is flush against the navigation bar.
There are no table section view headers, tableview margins are set to safe area. Has anyone else experienced that issue and if so, how did you solve it?
Here's a snapshot of the stackview captured from the device, in which we can clearly see the area being mis-rendered is well within the margins of the UINavigationBar:
I was also able to replicate the issue on a brand new project when setting up the following view structure:
The code to run this demo project is available on GitHub at: https://github.com/ekscrypto/stackoverflow-59033294
With the differing behaviours:
We can see physical device showing a bar of red between the navigation bar's content and the tableview; but that red bar is not visible in the simulator.
edit: 2019-11-25 16:45 EDT -- As per comments below I tried to force a refresh of the layout using:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 13.0, *) {
DispatchQueue.main.async {
self.navigationController?.navigationBar.setNeedsLayout()
self.navigationController?.navigationBar.layoutIfNeeded()
}
}
}
With and without the dispatch async, as well as with and without the layoutIfNeeded; it did not solve this particular issue for me.
Based on the answer at How to prevent gap between uinavigationbar and view in iOS 13?, which wasn't working for me, I solved my issue using the following code:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if #available(iOS 13.0, *) {
self.navigationController?.setNavigationBarHidden(true, animated: false)
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
}
Or in Objective-C:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if(#available(iOS 13, *)) {
[self.navigationController setNavigationBarHidden:true animated:false];
[self.navigationController setNavigationBarHidden:false animated:false];
}
}

Navigation bar gets blocked after pressing Cancel in UISearchController

I`m preparing app for iOS 13, and get bug with search controller in navigation bar. How to solve navigation bar glitch?
let search = UISearchController(searchResultsController: nil)
search.dimsBackgroundDuringPresentation = false
search.searchResultsUpdater = self
search.hidesNavigationBarDuringPresentation = false
self.definesPresentationContext = true
search.searchBar.isTranslucent = false
self.navigationItem.searchController = search
self.navigationItem.hidesSearchBarWhenScrolling = true
Press Cancel and navigation bar items becomes untouchable.
Pushing view controller leads to navigation bar item overlap.
I have created test project on git https://github.com/eKroman/TESTsearchBar
Bug appears on iOS 13 beta (tested on iPad) using from Xcode 11 from beta 7 (maybe older beta) to Xcode 11 GM seed 2.
Does not appear on simulators.
I encountered the same problem, if I cancel the searchBar and change the navigationItem.title then I have a double title 👍. It's like a ghost layer of the navigation bar stays here in the navigation controller.
This is how I fixed it:
searchController.hidesNavigationBarDuringPresentation = true
Probably best to use it until Apple fix this issue.
I also noticed that the back button switch to default color (blue), as if the navigationBar TintColor was reset.
Config:
- Xcode 11.0 (11A420a)
- iOS 13.1 (17A5844a)
For the back button reset to default color (blue) in #CoachThys's answer, I manage to work around it by the code below.
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
/* .. set other things on appearances */
appearance.buttonAppearance.normal.titleTextAttributes = [.foregroundColor: color]
standardAppearance = appearance
compactAppearance = appearance
scrollEdgeAppearance = appearance
}
However, I cannot find a way to work around the back indicator image which is still reset to blue color briefly.
Add custom backbutton with a image would fixed the new bug. It works well for me.
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeSpacer.width = -8
self.navigationItem.leftBarButtonItems = [negativeSpacer, leftBarButtonItem]

Is this new navigation bar behaviour in xcode 11 beta a bug or intended?

I noticed after compiling one of my apps in Xcode 11 beta, that navigation bars have no background when prefersLargeTitles is set. Is this intended behavior?
I noticed this is how the messages app works now when scrolling down and a large title is visible there is no nav bar background.
Here is the code used to set up the navBar attributes:
override func viewWillAppear(_ animated: Bool) {
let textAttributes = [NSAttributedString.Key.foregroundColor:ThemeManager.shared.default1]
self.navigationController?.navigationBar.largeTitleTextAttributes = textAttributes
self.navigationController?.navigationBar.titleTextAttributes = textAttributes
self.navigationController?.navigationBar.tintColor = ThemeManager.shared.default1
self.navigationController?.setNavigationBarHidden(false, animated: true)
self.navigationController?.navigationBar.prefersLargeTitles = true
let nav = self.navigationItem
nav.title = "My Profile"
}
Here are a couple of images showing the difference:
left, compiled on Xcode 10, right, Xcode 11 beta:
Once you scroll up on the 11 Beta version, the background fades back in. Note that apps that are not compiled in Xcode 11 beta will still behave in the normal way, only changes after compiling for some reason. Is this intended, and how would I bring back the original behavior?
This is intended behavior for iOS 13.
Apple's idea (terrible in my opinion) is that the title should merge with the content to show that it is related. Once you start scrolling, when content goes behind the title bar then the title bar will take the "correct" appearance.
The reason this is terrible is because everyone has currently planned all of their UI without this behavior. So the new behavior should be opt-in instead of forcing everyone to opt-out (i.e. the change breaks everyone's code and if you're going to break everyone's code at least you should be clear about how to keep the tried and true behavior of the last 10 years).
As in your case, the result looks horrible. The result looks horrible in my case too.
Apple doesn't give answers but says that you should be using
- scrollEdgeAppearance
From UINavigationBar in order to control the appearance of the bar when content is aligned top-of-content to bottom-of-navbar ... in my case this method returns nil though so I'm currently unsure how we're supposed to use this.
This seems to be discussed here as well:
New UINavigationBar appearance in detail pane of UISplitViewController in iOS 13
So the current workaround would seem to be this in your view controller:
- (void)viewDidLoad;
{
[super viewDidLoad];
if (#available(iOS 13,*)){
UINavigationBar *bar =self.navigationController.navigationBar;
bar.scrollEdgeAppearance = bar.standardAppearance;
}
}
It works, but if it's the intended approach, I don't know...
EDIT:
Doing this does seem to block any additional direct customization to the UINavigationBar as has been noted. Possible that adjusting the scrollEdgeAppearance from here is the way to go. Ugly. Ugly. Ugly.
EDIT: Progress... this is working now for managing the background. You need to call this instead of setting barTint directly.
#interface UINavigationBar (Compatibility)
- (void)setCompatibleTint:(UIColor *)fg andBarTint:(UIColor *)bg;
#end
#implementation UINavigationBar (Compatibility)
- (void)setCompatibleTint:(UIColor *)fg andBarTint:(UIColor *)bg;
{
self.tintColor = fg;
self.barTintColor = bg;
if (#available(iOS 13,*)){
// we need to tell it to adopt old style behavior first
UINavigationBarAppearance *appearance = self.standardAppearance;
appearance.backgroundColor = bg;
NSDictionary *attributes = self.titleTextAttributes;
appearance.titleTextAttributes = attributes;
attributes = self.largeTitleTextAttributes;
appearance.largeTitleTextAttributes = attributes;
self.scrollEdgeAppearance = appearance;
self.standardAppearance = appearance;
self.compactAppearance = appearance;
}
}
#end
I'm not entirely sure yet on the text attributes but it seems to flow from the background color. It's a complete PITA.
It would be nicer to set this as a subclass and override barTint but of course a lot of the UIKit objects create these bars themselves so you won't get the subclass.
Swift version of dbquarrel's solution.
First declare your textAttributes:
let textAttributes = [NSAttributedString.Key.foregroundColor:UIColor.red]
Use these in a UINavigationBarAppearance() to enable you to change the colour of the text in 3 different modes (scollEdge, standard and compact).
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 13.0, *) {
let appearance = UINavigationBarAppearance()
appearance.largeTitleTextAttributes = textAttributes
appearance.titleTextAttributes = textAttributes
let bar = self.navigationController?.navigationBar
bar?.scrollEdgeAppearance = appearance
bar?.standardAppearance = appearance
bar?.compactAppearance = appearance
} else {
// Fallback on earlier versions
}
}

a header unexpectedly shows up in all view controllers in iOS 10 and lower

all my view controllers and constraints are fine in iOS 11 and above but in iOS 10 and below a space created in all pages like the pictures below :
I tried even a simple web view in a viewcontroller with four constraints to safe area but I've got the same result.(good view in iOS 11 and above and a space to top in iOS 10 and below. and another strange thing is that some of my apps now have this problem and some don't :| . what should I do?
Can you try this?
if #available(iOS 11.0, *) {
scrollView.contentInsetAdjustmentBehavior = .never
} else {
self.automaticallyAdjustsScrollViewInsets = false
}
Note: Use (tableView, collectionView) instead of scrollview if you are using one.

iOS 9 iPad Keyboard get rid of "undo view"

How is it possible to get rid of this annoying "undo view" shown on the iPad in iOS 9.
Below is my own keyboard, above my accessory view. (just for testing purposes in this ugly color). Can someone please tell me how to remove it? Thanks in advance.
For Swift 2.0, You can place this code in viewDidLoad and it will work like a charm.
if #available(iOS 9.0, *) {
let item = yourTextView.inputAssistantItem
item.leadingBarButtonGroups = []
item.trailingBarButtonGroups = []
} else {
// Fallback on earlier versions
}
In Swift 3.0 and 4.0
youtTextField.inputAssistantItem.leadingBarButtonGroups.removeAll()
yourTextField.inputAssistantItem.trailingBarButtonGroups.removeAll()
However the best way to use this is to subclass a UITextfield and use the above code in the init() phase. Or to create an extension Instead of using it in the viewDidLoad for each and every textField.
This is code in Objective-C:
if (#available(iOS 9.0, *)) {
UITextInputAssistantItem* item = yourTextView.inputAssistantItem;
item.leadingBarButtonGroups = #[];
item.trailingBarButtonGroups = #[];
}