How to undo transparent navigation bar in iOS 11? - swift

I'm trying to create a transparent navigationBar in iOS 11.
I'm putting the following code in the VC, which works, but it stays transparent when another VC is pushed on top.
(I thought setting backgroundImage to nil again would work, but it doesn't.)
How do I get a white background when a new VC is pushed?
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationController?.navigationBar.prefersLargeTitles = false
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationBar.setBackgroundImage(nil, for: .default)
self.navigationController?.navigationBar.shadowImage = nil
}

You could add extension to simplify interaction with UINavigationBar
extension UINavigationBar {
func makeTransparent() {
self.setBackgroundImage(UIImage(), for: .default)
self.shadowImage = UIImage()
self.isTranslucent = true
}
func undoTransparency() {
self.setBackgroundImage(nil, for: .default)
}
func makeLargeAndTransparent() {
makeTransparent()
self.prefersLargeTitles = true
self.backgroundColor = .clear
self.barTintColor = *barTintColor*
self.tintColor = *tintColor*
self.largeTitleTextAttributes = [
.font: *font.of(size: 34)*,
.foregroundColor: *foregroundColor*
]
self.titleTextAttributes = [
.font: *font.of(size: 17)*,
.foregroundColor: *foregroundColor*
]
}
func makeDefault() {
undoTransparency()
self.prefersLargeTitles = false
self.barTintColor = *barTintColor*
self.tintColor = *tintColor*
self.titleTextAttributes = [
.font: *font.of(size: 17)*,
.foregroundColor: *foregroundColor*
]
}
}

Related

Swift: deallocate modally presented view controller

I have a modally presented SearchviewController that contains a UISearchController.
When swiping down it gets deallocated, but only if the searchControllers searchBar is not in editing mode. Only if I press its cancel button in advance, it gets deallocated.
How can I make sure it gets deallocated, even when in editing mode? There are definitely no strong self references within any closures...
Presenting ViewController:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
addButton()
}
func addButton() {
let mediumConfiguration = UIImage.SymbolConfiguration(scale: .large)
var checkButtonImage = UIImage(systemName: "plus", withConfiguration: mediumConfiguration)
checkButtonImage = checkButtonImage?.withTintColor(.label)
let button = UIButton(type: .contactAdd)
button.addTarget(self, action: #selector(onAddViewControllerButtonClicked(sender:)), for: .touchUpInside)
view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
}
#objc func onAddViewControllerButtonClicked(sender: UIButton) {
let viewController = SearchViewController()
viewController.view.backgroundColor = .secondarySystemBackground
let navigationController = UINavigationController()
navigationController.viewControllers = [viewController]
self.present(navigationController, animated: true)
}
}
Presented ViewController:
class SearchViewController: UIViewController, UISearchBarDelegate, UISearchResultsUpdating {
override func viewDidLoad() {
super.viewDidLoad()
configureSearchController()
}
var searchController: UISearchController?
func configureSearchController() {
//search
searchController = UISearchController(searchResultsController: nil)
searchController?.searchResultsUpdater = self
searchController?.searchBar.delegate = self
searchController?.hidesNavigationBarDuringPresentation = false
searchController?.searchBar.searchBarStyle = .minimal
searchController?.searchBar.keyboardType = .webSearch
self.navigationItem.searchController?.searchBar.backgroundColor = .clear
self.navigationItem.searchController = searchController
self.navigationItem.hidesSearchBarWhenScrolling = false
self.definesPresentationContext = true
self.navigationItem.searchController = searchController
}
func updateSearchResults(for searchController: UISearchController) {
return
}
//check deallocation
deinit { print("\(NSStringFromClass(type(of: self))): deallocated") }
}
Can you help with that?
Thank you in advance!
Adding
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.navigationItem.searchController = nil
}
to SearchViewController fixes the problem for me, but admittedly I have no idea as to why this is necessary.

Why I am not successfull to use segue programmatically?

I am using storyboard for ScreenOne, and I did not use the storyboard for ScreenTwo, I was coding as programmatically and until now no problem for me, but I am still not success to declare
"storyboardIdentifier" for ScreenTwo. Here there is an example but I don't understand how I will handle this example inside of the app. Any idea will be appreciated.
Screenshot:
ScreenTwo:
class ForgotPasswordEmailCheckController: UIViewController {
var storyboardId: String {
return (value(forKey: "ForgotPasswordEmailCheckController") as? String)!
}
Storyboard Controller (Also Embed this controller in Navigation Controller):
class FirstVC: UIViewController {
#IBOutlet weak var btn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
btn.addAction(UIAction(handler: { action in
let secondVC = SecVC()
self.navigationController?.pushViewController(secondVC, animated: true)
}), for: .touchUpInside)
}
}
Second Viewcontroller:
class SecVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blue
}
}
This is programmatically way to do it:
in sceneDelegate set your initial navigation controller:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.makeKeyAndVisible()
let controller = UINavigationController(rootViewController: MyController())
window?.rootViewController = controller
}
now configure your navigationBar in firstController, use my extension to do it:
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}
}
This is your first controller looks like:
class MyController: UIViewController {
let button = UIButton() // declare your button
override func viewDidLoad() {
super.viewDidLoad()
configureNavigationBar(largeTitleColor: .white, backgoundColor: .black, tintColor: .white, title: "My Vc", preferredLargeTitle: true) // set nav bar with exetnsion
view.backgroundColor = .white
view.addSubview(button)
button.backgroundColor = .systemBlue
button.layer.cornerRadius = 9
button.setTitle("My Button", for: .normal)
button.addTarget(self, action: #selector (handelGoToSecondVc), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
button.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16).isActive = true
button.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16).isActive = true
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
}
#objc func handelGoToSecondVc() {
let controller = SecondController()
controller.title = "second Vc"
navigationController?.pushViewController(controller, animated: true)
}
}
second controller:
class SecondController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
}
This is the result:
Complete code:
import UIKit
class MyController: UIViewController {
let button = UIButton() // declare your button
override func viewDidLoad() {
super.viewDidLoad()
configureNavigationBar(largeTitleColor: .white, backgoundColor: .black, tintColor: .white, title: "My Vc", preferredLargeTitle: true) // set nav bar with exetnsion
view.backgroundColor = .white
view.addSubview(button)
button.backgroundColor = .systemBlue
button.layer.cornerRadius = 9
button.setTitle("My Button", for: .normal)
button.addTarget(self, action: #selector (handelGoToSecondVc), for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
button.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16).isActive = true
button.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16).isActive = true
button.heightAnchor.constraint(equalToConstant: 50).isActive = true
button.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
}
#objc func handelGoToSecondVc() {
let controller = SecondController()
controller.title = "second Vc"
navigationController?.pushViewController(controller, animated: true)
}
}
class SecondController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
}
extension UIViewController {
func configureNavigationBar(largeTitleColor: UIColor, backgoundColor: UIColor, tintColor: UIColor, title: String, preferredLargeTitle: Bool) {
if #available(iOS 13.0, *) {
let navBarAppearance = UINavigationBarAppearance()
navBarAppearance.configureWithOpaqueBackground()
navBarAppearance.largeTitleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.titleTextAttributes = [.foregroundColor: largeTitleColor]
navBarAppearance.backgroundColor = backgoundColor
navigationController?.navigationBar.standardAppearance = navBarAppearance
navigationController?.navigationBar.compactAppearance = navBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navBarAppearance
navigationController?.navigationBar.prefersLargeTitles = preferredLargeTitle
navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.tintColor = tintColor
navigationItem.title = title
} else {
// Fallback on earlier versions
navigationController?.navigationBar.barTintColor = backgoundColor
navigationController?.navigationBar.tintColor = tintColor
navigationController?.navigationBar.isTranslucent = false
navigationItem.title = title
}
}
}

How to display a PopoverViewController from a custom Navigation Bar Right Button?

I created a custom Navigation Bar class as illustrated below, which I used across multiple ViewControllers:
import UIKit
import ChameleonFramework
class CustomUINavigationBar: UINavigationBar {
let navigationBarRightButtonView = UIView()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
convenience init(rightNavBarButtonTitleForNormalState: String, rightNavBarButtonImageForNormalState: String, rightNavBarButtonImageForHighlightedState: String, rightNavBarButtonTarget: Any?, rightNavBarButtonSelector: Selector, isNavBarTranslucent: Bool, navBarBackgroundColourHexCode: String, navBarBackgroundColourAlphaValue: CGFloat, navBarStyle: UIBarStyle, preferLargeTitles: Bool, navBarDelegate: UINavigationBarDelegate, navBarItemsHexColourCode: String, normalStateNavBarLeftButtonImage: String, highlightedStateNavBarLeftButtonImage: String, navBarLeftButtonTarget: Any?, navBarLeftButtonSelector: Selector, labelTitleText: String, titleLabelFontHexColourCode: String, labelTitleFontSize: CGFloat, labelTitleFontType: String) {
self.init()
addNavBarRightButton(rightNavBarButtonTitleForNormalState: rightNavBarButtonTitleForNormalState, rightNavBarButtonImageForNormalState: rightNavBarButtonImageForNormalState, rightNavBarButtonImageForHighlightedState: rightNavBarButtonImageForHighlightedState, rightNavBarButtonTarget: rightNavBarButtonTarget, rightNavBarButtonSelector: rightNavBarButtonSelector)
addNavBarLeftButton(normalStateNavBarLeftButtonImage: normalStateNavBarLeftButtonImage, highlightedStateNavBarLeftButtonImage: highlightedStateNavBarLeftButtonImage, navBarLeftButtonTarget: navBarLeftButtonTarget, navBarLeftButtonSelector: navBarLeftButtonSelector)
setupNavigationBarEssentials(isNavBarTranslucent: isNavBarTranslucent, navBarBackgroundColourHexCode: navBarBackgroundColourHexCode, navBarBackgroundColourAlphaValue: navBarBackgroundColourAlphaValue, navBarStyle: navBarStyle, preferLargeTitles: preferLargeTitles, navBarDelegate: navBarDelegate, navBarItemsHexColourCode: navBarItemsHexColourCode)
addTitleLabel(labelTitleText: labelTitleText, titleLabelFontHexColourCode: titleLabelFontHexColourCode, labelTitleFontSize: labelTitleFontSize, labelTitleFontType: labelTitleFontType)
}
let customNavigationBarItem = UINavigationItem()
func addTitleLabel(labelTitleText titleText: String, titleLabelFontHexColourCode hexCode: String, labelTitleFontSize fontSize: CGFloat, labelTitleFontType fontType: String) {
let navBarTitle = UILabel(frame: CGRect(x: 0, y: 0, width: frame.width, height: 44))
navBarTitle.text = titleText
navBarTitle.textColor = UIColor(hexString: hexCode)
navBarTitle.textAlignment = .center
navBarTitle.font = UIFont(name: fontType, size: fontSize)
navBarTitle.numberOfLines = 0
navBarTitle.lineBreakMode = .byWordWrapping
customNavigationBarItem.titleView = navBarTitle
}
func addNavBarLeftButton(normalStateNavBarLeftButtonImage: String, highlightedStateNavBarLeftButtonImage: String, navBarLeftButtonTarget: Any?, navBarLeftButtonSelector: Selector) {
let navBarLeftButton: UIButton = {
let button = UIButton()
let normalStateNavBarLeftButtonImage = UIImage(named: normalStateNavBarLeftButtonImage)
let highlightedStateNavBarLeftButtonImage = UIImage(named: highlightedStateNavBarLeftButtonImage)
button.setImage(normalStateNavBarLeftButtonImage, for: .normal)
button.setImage(highlightedStateNavBarLeftButtonImage, for: .highlighted)
button.addTarget(navBarLeftButtonTarget, action: navBarLeftButtonSelector, for: .touchUpInside)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let navBarLeftView: UIView = {
let view = UIView()
view.addSubview(navBarLeftButton)
NSLayoutConstraint.activate([
navBarLeftButton.topAnchor.constraint(equalTo: view.topAnchor),
navBarLeftButton.rightAnchor.constraint(equalTo: view.rightAnchor),
navBarLeftButton.bottomAnchor.constraint(equalTo: view.bottomAnchor),
navBarLeftButton.leftAnchor.constraint(equalTo: view.leftAnchor)
])
return view
}()
let navBarLeftButtonItem = UIBarButtonItem(customView: navBarLeftView)
customNavigationBarItem.leftBarButtonItem = navBarLeftButtonItem
}
func addNavBarRightButton(rightNavBarButtonTitleForNormalState: String, rightNavBarButtonImageForNormalState: String, rightNavBarButtonImageForHighlightedState: String, rightNavBarButtonTarget: Any?, rightNavBarButtonSelector: Selector) {
rightNavigationBarDropDownButton.setTitle(rightNavBarButtonTitleForNormalState, for: .normal)
rightNavigationBarDropDownButton.setImage(UIImage(named: rightNavBarButtonImageForNormalState), for: .normal)
rightNavigationBarDropDownButton.setTitleColor(.black, for: .normal)
rightNavigationBarDropDownButton.setTitleColor(.blue, for: .highlighted)
rightNavigationBarDropDownButton.addTarget(rightNavBarButtonTarget, action: rightNavBarButtonSelector, for: .touchUpInside)
rightNavigationBarDropDownButton.translatesAutoresizingMaskIntoConstraints = false
navigationBarRightButtonView.addSubview(rightNavigationBarDropDownButton)
NSLayoutConstraint.activate([
rightNavigationBarDropDownButton.topAnchor.constraint(equalTo: navigationBarRightButtonView.topAnchor),
rightNavigationBarDropDownButton.rightAnchor.constraint(equalTo: navigationBarRightButtonView.rightAnchor),
rightNavigationBarDropDownButton.leftAnchor.constraint(equalTo: navigationBarRightButtonView.leftAnchor),
rightNavigationBarDropDownButton.bottomAnchor.constraint(equalTo: navigationBarRightButtonView.bottomAnchor)
])
let navigationBarRightViewitem = UIBarButtonItem(customView: navigationBarRightButtonView)
customNavigationBarItem.rightBarButtonItem = navigationBarRightViewitem
}
func setupNavigationBarEssentials(isNavBarTranslucent: Bool, navBarBackgroundColourHexCode: String, navBarBackgroundColourAlphaValue: CGFloat, navBarStyle: UIBarStyle, preferLargeTitles: Bool, navBarDelegate: UINavigationBarDelegate, navBarItemsHexColourCode: String) {
items = [customNavigationBarItem]
isTranslucent = isNavBarTranslucent
barTintColor = UIColor(hexString: navBarBackgroundColourHexCode, withAlpha: navBarBackgroundColourAlphaValue)
barStyle = navBarStyle
prefersLargeTitles = preferLargeTitles
delegate = navBarDelegate
tintColor = UIColor(hexString: navBarItemsHexColourCode)
translatesAutoresizingMaskIntoConstraints = false
}
}
I then created an instance from the above custom Navigation Bar class into the viewController where I would like the custom Navigation bar to show. Then I tried to present the PopoverViewController whenever the user taps on the NavBarRightButtonItem, however, nothing is showing up, could please someone help me figuring out where did I go wrong, thanks a lot?
import UIKit
class BlueBookUniversalBeamsVC: UIViewController, UINavigationBarDelegate, UIPopoverPresentationControllerDelegate {
lazy var navigationBar = CustomUINavigationBar(rightNavBarButtonTitleForNormalState: "Sort By:", rightNavBarButtonImageForNormalState: "pullDownButton", rightNavBarButtonImageForHighlightedState: "pullUpButton", rightNavBarButtonTarget: self, rightNavBarButtonSelector: #selector(navigationBarRightButtonPressed(sender:)), isNavBarTranslucent: false, navBarBackgroundColourHexCode: "#FFFFFF", navBarBackgroundColourAlphaValue: 1.0, navBarStyle: .black, preferLargeTitles: false, navBarDelegate: self, navBarItemsHexColourCode: "#FF4F40", normalStateNavBarLeftButtonImage: "normalStateBackButton", highlightedStateNavBarLeftButtonImage: "highlightedStateBackButton", navBarLeftButtonTarget: self, navBarLeftButtonSelector: #selector(navigationBarLeftButtonPressed(sender:)), labelTitleText: "Universal Beams (UB)", titleLabelFontHexColourCode: "#000000", labelTitleFontSize: 16, labelTitleFontType: "AppleSDGothicNeo-Light")
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(navigationBar)
}
}
override func viewDidLayoutSubviews() {
setupConstraints()
}
#objc func navigationBarLeftButtonPressed(sender : UIButton) {
let viewControllerToGoTo = BlueBookTabController()
present(viewControllerToGoTo, animated: true, completion: nil)
}
#objc func navigationBarRightButtonPressed(sender : UIButton) {
let button = sender as? UIButton
let buttonFrame = button?.frame ?? CGRect.zero
let popoverContentController = self.storyboard?.instantiateViewController(withIdentifier: "PopoverViewController") as? PopoverViewController
popoverContentController?.modalPresentationStyle = .popover
if let popoverPresentationController = popoverContentController?.popoverPresentationController {
popoverPresentationController.permittedArrowDirections = .up
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = buttonFrame
popoverPresentationController.delegate = self
if let popoverController = popoverContentController {
present(popoverController, animated: true, completion: nil)
}
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
}
func popoverPresentationControllerShouldDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) -> Bool {
return true
}
func position(for bar: UIBarPositioning) -> UIBarPosition {
return UIBarPosition.topAttached
}
func setupConstraints() {
NSLayoutConstraint.activate([
navigationBar.leftAnchor.constraint(equalTo: view.leftAnchor),
navigationBar.rightAnchor.constraint(equalTo: view.rightAnchor),
navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
])
}
}
I managed to sort out my problem using the below code, what confused me at the beginning is that I am using a Standalone NavigationBar rather than a NavigationBar Controller:
#objc func navigationBarRightButtonPressed(sender : UIButton) {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let popOverViewController = storyboard.instantiateViewController(withIdentifier: "PopoverViewController")
popOverViewController.modalPresentationStyle = .popover
let popover = popOverViewController.popoverPresentationController!
popover.delegate = self
popover.permittedArrowDirections = .up
// The sourceView in the below code line represents the view containing the anchor rectangle for the popover:
popover.sourceView = navigationBar.navigationBarRightButtonView
// The sourceRect in the below code line represents The rectangle in the specified view in which to anchor the popover:
popover.sourceRect = navigationBar.navigationBarRightButtonView.bounds
present(popOverViewController, animated: true, completion:nil)
}

UISearchController - Black Rectangle

I'm implementing a simple tableViewController with UISearchcontroller.
The problem is that every time that I press the search field then a black rectangle appear right after the keyboard shows up.
I also tried to use definesPresentationContext and searchBarStyle but it keep showing the rectangle. On the other hand, it looks like doesn't happen in the simulator since there is no keyboard.
Update: Below some photos.
ViewController:
class ListGlobalViewController: UITableViewController, StoryboardSceneBased, ViewModelBased {
static var sceneStoryboard: UIStoryboard = UIStoryboard(name: "DataSelectorViewController", bundle: Bundle.main)
// --------------------
// MARK: - Properties
// --------------------
var viewModel: ListGlobalViewModel!
private let disposeBag = DisposeBag()
private let searchController: UISearchController = {
let searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.searchBarStyle = .minimal
searchController.dimsBackgroundDuringPresentation = false
searchController.hidesNavigationBarDuringPresentation = true
return searchController
}()
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
configure(with: viewModel)
navigationItem.largeTitleDisplayMode = .automatic
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.searchController.isActive = false
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
}
// --------------------
// MARK: - Functions
// --------------------
func configure(with viewModel: ListGlobalViewModel) {
self.tableView.delegate = nil
self.tableView.dataSource = nil
viewModel.outputs.listDataObservable.bind(to: self.tableView.rx.items(cellIdentifier: "listGlobalCell", cellType: ListGlobalCell.self)) { (index, model, cell) in
cell.model = model
}.disposed(by: disposeBag)
searchController.searchBar.rx.text.filterNil().throttle(1, scheduler: MainScheduler.instance).distinctUntilChanged().subscribe(viewModel.inputs.searchBarObservable).disposed(by: disposeBag)
}
}
Navigation Default Values:
let controller = UINavigationController()
controller.navigationBar.isTranslucent = false
controller.navigationBar.prefersLargeTitles = true
controller.definesPresentationContext = true
controller.navigationBar.titleTextAttributes = [ NSAttributedString.Key.font: UIFont.bold(size: 24), NSAttributedString.Key.foregroundColor: UIColor.black ]
if #available(iOS 11, *) {
controller.navigationBar.largeTitleTextAttributes = [ NSAttributedString.Key.font: UIFont.bold(size: 33), NSAttributedString.Key.foregroundColor: UIColor.black ]
}
return controller
Pictures:
Bugged
Use UITextField instead if UISearchBar. You can give any design to uitextfield. UISearch bar has limited designable attributes. Also you can reach any search function with textfield.

BarButtonItem Doesn't Show button after added

I want custom navigation item as facebook app.
Have two buttons and one UISearchBar. Buttons is leftBarButtonItem and rightBarButtonItem. UISearchBar is titleView.
to make searchbar in titleview become wide i removed two buttons by set it to nil as image below. and i add two buttons again when searchBarCancelButton clicked but the buttons doesn't shown.
Could u help me ?
when click searchBarCancelButton i want it to show as below
Code I have try:
func updateSearchResultsForSearchController(searchController: UISearchController) {
if navigationItem.rightBarButtonItem != nil {
self.navigationItem.rightBarButtonItem = nil
self.navigationItem.leftBarButtonItem = nil
}
}
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
navigationItem.setLeftBarButtonItem(getBarButtonItem("info", buttonfor: "left"), animated: false)
navigationItem.setRightBarButtonItem(getBarButtonItem("more_‌​icon", buttonfor: "right"), animated: false)
}
extension MainviewCtrl : UISearchResultsUpdating {
func updateSearchResultsForSearchController(searchController: UISearchController) {
if navigationItem.rightBarButtonItem != nil {
self.navigationItem.rightBarButtonItem = nil
self.navigationItem.leftBarButtonItem = nil
}
}
}
extension MainviewCtrl : UISearchBarDelegate {
func searchBarCancelButtonClicked(searchBar: UISearchBar) {
navigationItem.setLeftBarButtonItem(getBarButtonItem("info", buttonfor: "left"), animated: false)
navigationItem.setRightBarButtonItem(getBarButtonItem("more_icon", buttonfor: "right"), animated: false)
}
}
class MainviewCtrl: UIViewController , UISearchControllerDelegate {
lazy var searchController : UISearchController = {
let _searchController = UISearchController(searchResultsController: nil)
_searchController.searchResultsUpdater = self
_searchController.dimsBackgroundDuringPresentation = false
_searchController.hidesNavigationBarDuringPresentation = false
_searchController.searchBar.delegate = self
_searchController.searchBar.tintColor = UIColor.whiteColor()
_searchController.searchBar.searchBarStyle = UISearchBarStyle.Minimal
var textFieldInsideSearchBar = _searchController.searchBar.valueForKey("searchField") as? UITextField
textFieldInsideSearchBar?.textColor = UIColor.whiteColor()
return _searchController
}()
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.titleView = searchController.searchBar
definesPresentationContext = true
addBarButtonItems()
}
func addBarButtonItems(){
navigationItem.leftBarButtonItem = getBarButtonItem("info", buttonfor: "left")
navigationItem.rightBarButtonItem = getBarButtonItem("more_icon", buttonfor: "right")
}
func getBarButtonItem(imagename : String , buttonfor : String)-> UIBarButtonItem!{
let image = (UIImage(named: imagename))!.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
switch buttonfor.lowercaseString {
case "left":
return (UIBarButtonItem(image: image, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(MainviewCtrl.infoAction)))
case "right":
return (UIBarButtonItem(image: image, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(MainviewCtrl.moreAction)))
default : break ;
}
return UIBarButtonItem()
}
updateSearchResultsForSearchController will get called again after you click cancel button and make those items nil. you can check if the search controller is active before setting them to nil in updateSearchResultsForSearchController:
func updateSearchResultsForSearchController(searchController: UISearchController) {
if navigationItem.rightBarButtonItem != nil && searchController.active {
self.navigationItem.rightBarButtonItem = nil
self.navigationItem.leftBarButtonItem = nil
}
}