iOS 11 Logo and title in NavigationBar - ios

I have been searching and trying for days but since it's a new thing there's not much information available (or I can't find them).
Anyway, I am trying to get use of new NavBar features in iOS 11 but I want to put both a logo and a large title (of each ViewController) in my NavBar. Something like the screenshot below:
How is it possible to implement this?
Side Hint:
For same app in iOS 10 I set the logo to show instead of titleView in NavBar but now in newer version we want to add the Title too.
Thanks in advance

Without your code sample it's hard to say what goes wrong for you, but this just works:
override func viewDidLoad() {
super.viewDidLoad()
if #available(iOS 11, *) {
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.largeTitleDisplayMode = .always
title = "Your title"
}
let titleImageView = NavigationImageView()
titleImageView.image = UIImage(named: "yourImageName")
navigationItem.titleView = titleImageView
}
EDIT: To set custom size for your title view you can subclass your UIView (UIImageView) and override sizeThatFits
class NavigationImageView: UIImageView {
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: 50, height: 50)
}
}

Did you try setting a background image for your navbar? Like this:
// Set Navigation bar background Image
let navBgImage:UIImage = UIImage(named: "[image.jpg]")!
self.navigationController!.navigationBar.setBackgroundImage(navBgImage, for: .default)

Related

Change image tint, title tint, background and so on in new UITabbar from iOS 13

I faced a weird problem. I wanted to change the colors of my tabBar in just one of my view controllers of my tabBar. How do I achieve this in iOS > 13?
After searching a lot and finding no working solutions, I succeeded by luck.
I found out that you must set an appearance object before I can change them!!
But if you set appearance before the override function endAppearanceTransition() of UITabbar it is working, but not anymore. finally, this way worked:
Set an empty appearance object at viewDidLoad of one of the view Controllers or UITabbarViewcontroller to be executed one time:
override func viewDidLoad() {
super.viewDidLoad()
tabBarController?.tabBar.standardAppearance = UITabBarAppearance()
}
Then you can use updating like this at anytime:
let attrs = [NSAttributedString.Key.foregroundColor: UIColor.green]
tabBarController?.tabBar.backgroundColor = barColor
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.selected.iconColor = .green
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.normal.iconColor = .green
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.normal.titleTextAttributes = attrs
tabBarController?.tabBar.standardAppearance.stackedLayoutAppearance.selected.titleTextAttributes = attrs

Unable to change navigation bar color during runtime via code?

I tested against iOS 14.5
We would like to provide ability to change the navigation bar color during runtime.
However, I notice the following code no longer has any effect.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
navigationController?.navigationBar.backgroundColor = UIColor.red
navigationController?.navigationBar.tintColor = UIColor.red
UINavigationBar.appearance().barTintColor = UIColor.red
}
}
But, if I did it directly in Storyboard, it works just fine.
We would like to have ability to change the various different color during runtime (via user button clicked)
Does anyone has any idea why the above code broken?
Thanks.
p/s I can confirm the navigationController is not nil.
On iOS 13 & above, you have to use new UINavigationBarAppearance api to get the correct color.
public extension UINavigationBar {
func applyPlainAppearanceFix(barTintColor: UIColor, tintColor: UIColor) {
if #available(iOS 13, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = barTintColor
self.standardAppearance = appearance
self.compactAppearance = appearance
self.scrollEdgeAppearance = appearance
}
self.isTranslucent = false
self.barTintColor = barTintColor
self.backgroundColor = barTintColor
self.tintColor = tintColor
}
}
From the call site it should look like
navigationController?.navigationBar.applyPlainAppearanceFix(barTintColor: .red, tintColor: .white)
Could you try adding this in your AppDelegate and I think it will work, if you didn't want it for all the app then your code is working fine, I've used it and it's working like in the image below:

How to change UIDocumentInteractionController Done button text and background color

How to change the background color and text color of done button? Is there a way that I can change the navigationbar color and navigation bar title color and bottom bar color also? Attached screenshot for reference:
I solved it. Here is the code working for me perfectly:
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
UINavigationBar.appearance().barTintColor = Colors.redColor()
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white, NSFontAttributeName: UIFont.systemFont(ofSize: 14, weight: UIFontWeightBold)]
return self
}
It's a little hacky as its relying on the fact that QLPreviewController is the class implementing the UIDocumentInteractionController but something like this is the least intrusive solution. Do it before you display the UIDocumentInteractionController
import QuickLook
UIBarButtonItem.appearance(whenContainedInInstancesOf [QLPreviewController.self]).tintColor = UIColor.black
I have a idear to change the bar color:
let allNavigationBar = UINavigationBar.appearance()
allNavigationBar.barTintColor = UIColor.red // change the bar background color
allNavigationBar.tintColor = UIColor.black // change the Done button's tintColor
let alloolbar = UIToolbar.appearance()
allToolbar.barTintColor = UIColor.red // dones't work, try backgroundImage
allToolbar.backgroundColor = UIColor.blue // dones't work
allToolbar.tintColor = UIColor.brown // change the toolbar's item tint color
but this method has a great effect,all your UINavigationBarand UIToolBar will make that change.
Hope anyone else can give a better solusion.
You can change the tint color of the window temporally.
func presentDocument() {
//present the controller here
self.appDelegate.window.tintColor = UIColor.red
}
Then change it back later:
func documentInteractionControllerDidEndPreview(documentInteractionController) { //replace parameter with your uidocumentviewinteractioncontroller
self.appDelegate.window.tintColor = UIColor.white
}
#Dee. I guess you have asked this part in one of your other question. In that case you were not able to show that preview controller. In that question suggested answer is to return "self" from that delegate method. If you implement that correctly then your preview will use same navigation bar colour as its parent controller is using. I mean if you have opened UIDocumentInteractionController directly from some ViewController then UIDocumentInteractionController will use its parent viewController's navigation bar colour. This may help you to change Done button colour
Try this : (You need to implement UIDocumentInteractionControllerDelegate)
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self.navigationController ?? self
}
let QLNavAppearance = UINavigationBar.appearance(whenContainedInInstancesOf: [QLPreviewController.self])
QLNavAppearance.tintColor = UIColor.red // some
QLNavAppearance.barTintColor = UIColor.red // some
QLNavAppearance.backgroundColor = UIColor.red // some

UINavigationBar : Add SearchBar as TitleView

I want to add uisearchbar in place of title of controller.
I am facing 2 problems currently.
1)
I do not know from where this gray background is coming. Please check this picture.
2) I need this searchbar in other inner screens also. But when I push another controller this searchbar is removed.
Here is my code :
// Seachbar Container View
let searchBarContainer = ERView(frame: CGRectMake(0,0,280,44))
searchBarContainer.autoresizingMask = [.FlexibleWidth]
searchBarContainer.backgroundColor = UIColor.clearColor()
// Search Bar
let searchBar = ERSearchBar(frame: searchBarContainer.bounds)
searchBarContainer.addSubview(searchBar)
// Add View as Title View in Navigation Bar
self.navigationController!.navigationBar.topItem?.titleView = searchBarContainer
Here is Code of my UISearchBar Class
func commonInit() -> Void {
// Update UI
if let searchField = self.valueForKey("searchField") as? UITextField{
// To change background color
searchField.backgroundColor = UIColor.appNavigationBarDarkRedColor()
// Tint Color
if let leftViewRef = searchField.leftView {
leftViewRef.tintColor = UIColor.whiteColor()
}else if let imgLeftView = searchField.leftView as? UIImageView{
imgLeftView.tintColor = UIColor.whiteColor()
}
// Font Color
searchField.font = UIFont.robotoRegularFont(WithSize: 14.0)
// Text Color
searchField.textColor = UIColor.whiteColor()
// PlaceHolder Attributes
searchField.attributedPlaceholder = NSAttributedString(string: "Search", attributes: [NSForegroundColorAttributeName:UIColor.whiteColor()])
}
self.setImage(UIImage(named: "ic_search_white"), forSearchBarIcon: UISearchBarIcon.Search, state: UIControlState.Normal)
// To change placeholder text color
}
Please someone help me here.
For 1) Set the searchBarStyle property to minimal. This will provides no default background color in UIsearchBar.
2)I'm not quite sure what'd you mean by "inner screen". But if what you want is a Search Bar that can work across different view controllers, UISearchController is the one you're looking for.
You can fine the Apple sample code here

Change the button titles on SLComposeServiceViewController?

Is there a way to change the button titles on the SLComposeServiceViewController? I tried to change the bar button items on the navigation item, but those aren't the right buttons.
Simply accessing from navigationController!.navigationBar does the charm. The following should help.
self.navigationController!.navigationBar.topItem!.rightBarButtonItem!.title = "Save"
I just found a way to do it:
class CustomServiceViewController: SLComposeServiceViewController {
override func viewDidLoad() {
let navigationBar = view.subviews.first?.subviews?.last? as? UINavigationBar
let postButton = navigationBar?.subviews.last? as? UIButton
let cancelButton = navigationBar?.subviews.last? as? UIButton
postButton?.setTitle("Done", forState: .Normal)
}
}
Be warned - it's a fragile solution, based on undocumented internals of SLComposeServiceViewController
The answer by Kasztan no longer works with the latest iOS; here is the latest fragile solution..
class CustomServiceViewController: SLComposeServiceViewController {
override func viewDidLoad() {
let navigationBar = view.subviews.last?.subviews?.last? as? UINavigationBar
let postButton = navigationBar?.subviews[3] as? UIButton
postButton?.setTitle("Done", forState: .Normal)
}
}
EDIT #3: Solution working on iOS 9 and iOS 10 beta
The previous approach stopped working with iOS 9, but the following seems to work again (tested on iOS 9 and 10 beta 2):
1) First, you need to add a UIFont class extension to check if a button font is bold (this, because the Post button is always bold); here's how.
2) Then, in viewDidAppear:, we need the following code (an updated version of the code I wrote in Edit 2):
if let navigationBar = self.navigationController?.navigationBar {
// First, let's set backgroundColor and tintColor for our share extension bar buttons
navigationBar.backgroundColor = UIColor.darkGrayColor()
navigationBar.tintColor = UIColor.whiteColor()
if let navBarSubviews = navigationBar.subviews as? [UIView] {
for eachView in navBarSubviews {
if let navBarButton = eachView as? UIButton {
// Second, let's set our custom titles for both buttons (Cancel and Post); checking for the title wouldn't work for localized devices, so we check if the button is bold (Post) or not (Cancel) via the UIFont class extension above.
let buttonFont : UIFont? = navBarButton.titleLabel?.font
if buttonFont?.isBold == true {
navBarButton.setTitle("Save", forState: .Normal)
} else {
navBarButton.setTitle("Cancel", forState: .Normal)
}
}
}
}
}
Of course, this works now, but it will probably break again in the future...
EDIT #2: I made it work on a device with iOS 8.4 :)
Turns out I was wrong, after spending an unreasonable amount of time on this I've been able to both change the color of the buttons and their text.
Here's my code, that needs to be put inside ViedDidAppear() (if you place it in viewDidLoad() it won't work!):
if let navigationBar = self.navigationController?.navigationBar {
// First, let's set backgroundColor and tintColor for our share extension bar buttons
navigationBar.backgroundColor = UIColor.darkGrayColor()
navigationBar.tintColor = UIColor.whiteColor()
if let navBarSubviews = navigationBar.subviews as? [UIView] {
for eachView in navBarSubviews {
if let navBarButton = eachView as? UIButton {
// Second, let's set our custom titles for both buttons (Cancel and Post); checking for the title wouldn't work on localized devices, so we check if the current button is emphasized (Post) or not (Cancel) via an UIFontDescriptor.
let fontDescriptor : UIFontDescriptor? = navBarButton.titleLabel?.font.fontDescriptor()
if let descriptor = fontDescriptor {
let fontAttributes : NSDictionary = descriptor.fontAttributes()
var buttonFontIsEmphasized : Bool? = fontAttributes["NSCTFontUIUsageAttribute"]?.isEqualToString("CTFontEmphasizedUsage")
if buttonFontIsEmphasized == true {
navBarButton.setTitle("Save", forState: .Normal)
} else {
navBarButton.setTitle("Cancel", forState: .Normal)
}
}
}
}
}
}
Still, I'm not sure this should be done on a shipping app nor it would pass App Review (it should, though, because it doesn't mess with private APIs).
Also, it should be noted that this could break anytime, even though it shouldn't be as easily breakable as the previous solutions (it iterates through the subviews and attempts downcasting them, so a small change in the view hierarchy shouldn't render it useless); my expectations is that, even if in the future it stops working, it shouldn't crash the Share Extension.
Original answer
I believe what you (and I) want to do is not possible anymore, possibly by design. Here's why:
Inspired by #Kasztan and #Paito answers, I tried this in viewDidLoad() of my ShareViewController:
for eachView in view.subviews {
println("1")
for eachSubView in eachView.subviews {
println("2")
if let navigationBarView = eachSubView as? UINavigationBar {
println("3")
for eachNavBarSubView in navigationBarView.subviews {
println("4")
if let navBarButton = eachNavBarSubView as? UIButton {
println("5")
println(navBarButton.titleForState(.Normal))
navBarButton.setTitleColor(UIColor.redColor(), forState: .Normal)
navBarButton.setTitle("My text", forState: .Normal)
navBarButton.tintColor = UIColor.redColor()
navBarButton.setNeedsLayout()
navBarButton.layoutIfNeeded()
}
}
}
}
}
Not that I believe something like this should ship in an app, but as a proof of concept this should have worked and, in theory, should be a bit less breakable with future releases of the OS.
Except, it didn't work for me on iOS 8.4: I see all the checkpoint messages logged, from 1 to 5, some of them multiple times (as it should be, since the code tries every possible subview).
The "5" message is logged twice, which makes sense since it means that it successfully downcast both the buttons, Cancel and Post, but not the text nor the color is changed from the default.
My conclusion is that something in Apple's code prevents us to change the appearance of those buttons.
Of course, if anyone finds a solution, I'd be glad to downvote my own answer (if it can be done, I'm note sure) ;)
EDIT #1: One last check, I logged the button title too, after the buttons downcast (5), and yes, I got Optional("Cancel") and Optional("Post") in the console, so this solution gets the right buttons, but they can't be edited.

Resources