CNContactViewController navigation bar colour not appearing when i click Create New Contact option. See my screens for 1st time it's ok, but when i click Create New Contact i'm not getting navigation bar colour and not visible back button.
1st screen
2nd screen
In older versions
My code is
if #available(iOS 9.0, *) {
let store = CNContactStore()
let contact = CNMutableContact()
let homePhone = CNLabeledValue(label: CNLabelHome, value: CNPhoneNumber(stringValue : self.mobile ?? ""))
contact.phoneNumbers = [homePhone]
let controller = CNContactViewController(forUnknownContact : contact)
controller.contactStore = store
controller.delegate = self
if #available(iOS 10.0, *) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(0.1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: {
//Set status bar background colour
let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
statusBar?.backgroundColor = UIColor.red
//Set navigation bar subView background colour
for view in controller.navigationController?.navigationBar.subviews ?? [] {
view.tintColor = UIColor.white
view.backgroundColor = UIColor.red
}
})
}
navigationController?.pushViewController(controller, animated: true)
}
And one more is by default phone number: (913) 351-5518
I would suggest to display a CNConctactViewController within a UINavigationController in Popover Modal Presentation style, and add a few button to return to the main application. This implementation seams not trivial as reported by rumours over the net.
Let me share a few pieces of my code (swift 5).
The major class:
class MyViewController: UITableViewController, UIPopoverPresentationControllerDelegate {
var contactViewController = CNContactViewController()
...
#objc func dismissContactViewController() {
contactViewController.dismiss(animated: true, completion: nil)
}
}
The extension:
extension MyViewController: CNContactViewControllerDelegate {
func openCNContactViewController(willAppearWith: CNContact, type: ContactType) {
switch type {
case .forContact:
contactViewController = CNContactViewController(for: willAppearWith)
contactViewController.allowsEditing = false
break
case .forNewContact:
contactViewController = CNContactViewController(forNewContact: willAppearWith)
contactViewController.allowsEditing = true
break
case .forUnknowContact:
contactViewController = CNContactViewController(forUnknownContact: willAppearWith)
contactViewController.allowsEditing = true
break
}
contactViewController.allowsActions = true
contactViewController.contactStore = globalContactStore
contactViewController.hidesBottomBarWhenPushed = true
contactViewController.delegate = self
// define the button (or select a default one)
let button = UIButton(type: .custom)
button.setTitleColor(self.view.tintColor, for: .normal)
button.setTitle("My app name", for: .normal)
button.addTarget(self, action: #selector(dismissContactViewController), for: .touchUpInside)
let closeButton = UIBarButtonItem(customView: button)
closeButton.style = .plain
// add flexible space
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
// add to toolbar
contactViewController.setToolbarItems([flexibleSpace, closeButton, flexibleSpace], animated: false)
let navigationVC = UINavigationController(rootViewController: contactViewController)
// show toolbar
navigationVC.setToolbarHidden(false, animated: false)
// set navigation presentation style
navigationVC.modalPresentationStyle = .popover
// present view controller
self.present(navigationVC, animated: true, completion: nil)
}
The result
Related
In Apple's documentation on Sheet Views, they demonstrate how to instantiate a view controller that displays a Bottom Sheet with a "close" button on the right-hand side. Consider the photo below:
I am having a hard time replicating this. When I present the Sheet View in a NavigationController, and explicitly add a close button, I can see the close button but the sheet becomes a .large() detent. Their photo suggests they are achieving this with a .medium() detent. Documentation for UISheetPresentationController shows no other alternative. Any idea what I am doing wrong?
My SheetController:
override func viewDidLoad() {
....
navigationItem.rightBarButtonItem = UIBarButtonItem.init(barButtonSystemItem: .done, target: self, action: #selector(closeSheet))
....
}
In a different controller, a button click initiates the presentation of the sheetController:
#objc func showTheSheet() {
let updateController = MySheetController()
if let sheet = updateController.sheetPresentationController {
sheet.detents = [.medium()]
sheet.largestUndimmedDetentIdentifier = nil
sheet.prefersGrabberVisible = true
sheet.prefersScrollingExpandsWhenScrolledToEdge = true
sheet.prefersEdgeAttachedInCompactHeight = true
sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
let navController = UINavigationController(rootViewController: updateController)
self.present(navController, animated: true, completion: nil)
}
Ah, the answer is to wrap the nav controller into the sheet. Silly mistake, but might help someone.
#objc func updateAction() {
let updateController = MySheetController()
let navController = UINavigationController(rootViewController: updateController)
if let sheet = navController.sheetPresentationController {
sheet.detents = [.medium()]
sheet.largestUndimmedDetentIdentifier = nil
sheet.prefersGrabberVisible = true
sheet.prefersScrollingExpandsWhenScrolledToEdge = true
sheet.prefersEdgeAttachedInCompactHeight = true
sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
self.present(navController, animated: true, completion: nil)
}
I have a tab bar controller that shows 5 tabs. It shows perfectly in iOS 12 or earlier as shown here
.
But if I run the same in iOS 13, the design is totally messed up
.
It totally loses the scroll view insets, and it is also not adjusting the bottom insets of my menus table view. some of the menus are hidden in the bottom. they are not scrolling up. and this is the code that I'm using in UITabBarController
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
guard let user = user else {
appDelegate.instituteSelectionView()
return
}
var dashBoard: UINavigationController
var menus: UINavigationController? = nil
// Creating all the view controllers for tabs.
if user.role.caseInsensitiveCompare("student") == .orderedSame {
let dashBoardVC = mainStoryBoard.instantiateViewController(withIdentifier: "DashboardVC") as! DashboardVC
dashBoardVC.menus = ContentProvider.getMenus()
dashBoardVC.school = user.school
dashBoard = UINavigationController(rootViewController: dashBoardVC)
dashBoard.navigationBar.prefersLargeTitles = true
} else {
let dashBoardVC = mainStoryBoard.instantiateViewController(withIdentifier: "DashboardWidgetsTableViewController") as! DashboardWidgetsTableViewController
dashBoardVC.user = user
dashBoardVC.title = "Dashboard"
dashBoard = UINavigationController(rootViewController: dashBoardVC)
let menusVC = mainStoryBoard.instantiateViewController(withIdentifier: "MenusTableViewController") as! MenusTableViewController
menusVC.setMenus(ContentProvider.getMenusForStaff())
menus = UINavigationController(rootViewController: menusVC)
}
dashBoard.tabBarItem = UITabBarItem(title: "Dashboard", image: #imageLiteral(resourceName: "dashboard"), tag: 0)
if menus != nil {
menus?.navigationBar.prefersLargeTitles = true
menus?.tabBarItem = UITabBarItem(title: "Menus", image: #imageLiteral(resourceName: "menu-1"), tag: 1)
}
let notificationVC = mainStoryBoard.instantiateViewController(withIdentifier: "NotificationsTabTableViewController") as! NotificationsTabTableViewController
notificationVC.user = user
let notification = UINavigationController(rootViewController: notificationVC)
notification.tabBarItem = UITabBarItem(title: "Notifications", image: #imageLiteral(resourceName: "bell"), tag: 3)
notification.tabBarItem.badgeValue = user.badge > 0 ? String(user.badge) : nil
notification.navigationBar.prefersLargeTitles = true
let settingsVC = mainStoryBoard.instantiateViewController(withIdentifier: "SettingsTabTableViewController") as! SettingsTabTableViewController
settingsVC.user = user
let settings = UINavigationController(rootViewController: settingsVC)
settings.tabBarItem = UITabBarItem(title: "Settings", image: #imageLiteral(resourceName: "settings"), tag: 4)
settings.navigationBar.prefersLargeTitles = true
let accountsVC = mainStoryBoard.instantiateViewController(withIdentifier: "AccountsTableViewController") as! AccountsTableViewController
let accounts = UINavigationController(rootViewController: accountsVC)
accounts.tabBarItem = UITabBarItem(title: "Accounts", image: #imageLiteral(resourceName: "user_group_man_man"), tag: 5)
accounts.navigationBar.prefersLargeTitles = true
mViewControllers = [dashBoard, notification, settings, accounts]
if menus != nil {
mViewControllers.insert(menus!, at: 1)
}
// Adding logo and profile button to navigation bar of each view controller.
for vc in mViewControllers {
if let nVC = vc as? UINavigationController, let vc = nVC.topViewController {
let logo = UIImageView(image: #imageLiteral(resourceName: "educare logo"))
logo.contentMode = .scaleAspectFill
logo.clipsToBounds = true
logo.widthAnchor.constraint(equalToConstant: 24).isActive = true
logo.heightAnchor.constraint(equalToConstant: 24).isActive = true
let profileButton = UIButton(type: .custom)
profileButton.widthAnchor.constraint(equalToConstant: 24).isActive = true
profileButton.heightAnchor.constraint(equalToConstant: 24).isActive = true
profileButton.imageView?.layer.cornerRadius = 12
if #available(iOS 13.0, *) {
let image = UIImage(systemName: "person.crop.circle")
profileButton.sd_setImage(with: URL(string: user.image), for: .normal, placeholderImage: image)
} else {
profileButton.sd_setImage(with: URL(string: user.image), for: .normal, placeholderImage: #imageLiteral(resourceName: "user_circle"))
}
profileButton.addTarget(self, action: #selector(openProfile), for: .touchUpInside)
let logoButtonItem = UIBarButtonItem(customView: logo)
let profileButtonItem = UIBarButtonItem(customView: profileButton)
vc.navigationItem.leftBarButtonItem = logoButtonItem
vc.navigationItem.rightBarButtonItems = [profileButtonItem]
}
}
setViewControllers(mViewControllers, animated: true)
}
Update: Actually the first view controller in the tab bar controller renders correctly but the rest of the view controllers have that ugly navigation bar.
I Solved the problem. turns out it was the transition animation (from the initial view controller to the main tab bar controller) that was causing the problem. So i changed the code from this
if animated {
UIView.transition(from: (window?.rootViewController?.view)!, to: viewController.view, duration: duration, options: animationOptions) { (completed) in
if completed {
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
}
} else {
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
to this
guard let window = UIApplication.shared.keyWindow else { return }
window.rootViewController = viewController
window.makeKeyAndVisible()
if animated {
UIView.transition(with: window, duration: duration, options: animationOptions, animations: {})
}
I've a ViewController as popup to pick a date on UIDatePicker. But when, this popup opens, the background is covered by new background color. I tried choose a opacity of color, but this not works.
I use a UILabel to handler click and open a new ViewController.
override func viewDidLoad() {
super.viewDidLoad()
let tapDateSelectExpiration = UITapGestureRecognizer(target: self, action: #selector(handleSelectDateExpiration))
let tapDateSelectValidity = UITapGestureRecognizer(target: self, action: #selector(handleSelectDateValidity))
let tapDateSelectOrder = UITapGestureRecognizer(target: self, action: #selector(handleSelectDateOrder))
lblDataPedido.isUserInteractionEnabled = true
lblDataValidade.isUserInteractionEnabled = true
lblDataExpiracao.isUserInteractionEnabled = true
lblDataPedido.addGestureRecognizer(tapDateSelectOrder)
lblDataValidade.addGestureRecognizer(tapDateSelectValidity)
lblDataExpiracao.addGestureRecognizer(tapDateSelectExpiration)
}
#objc func handleSelectDateExpiration(_ sender : UILabel) {
print("handleSelectDateExpiration")
var vcSelectDate = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerSelectDate") as! ViewControllerSelectDate
vcSelectDate.typeDate = "DateExpiration"
self.present(vcSelectDate,animated: true,completion: nil)
}
// Other funcs as above.
MainLayout:
DatePicker layout with backgroud not transparent:
Storyboard:
You can try
let vc = self.storyboard?.instantiateViewController(withIdentifier: "dateView") as! dateViewController
vc.delegate = self
vc.providesPresentationContextTransitionStyle = true;
vc.definesPresentationContext = true;
vc.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(vc, animated: false, completion: nil)
and select transparent background like this
or in IB
I've created an App which has three storyboards. ( & multiple VC's) I am creating a global NavigationItem class, that I can enter in storyboard so every view controller inherits the same information and I only have to code one page rather than copying and pasting into each VC.
I want to set the title programmatically. The title can change depending on which storyboard is active and what size phone is present. i.e full title or shorthand if it is displaying on an iPhone SE.
I can't use. UIStoryboard as a bool, as it doesn't conform. How can I tell which storyboard I'm in, so it can set the title in an if statement? The code i've written is wrong and doesn't work for the storyboard.
My code setup so far for my NavigationItemCustom class is bellow I am finding it difficult to find which storyboard i'm in? Can anyone push me in the right direction, please. My code is as follows:
import UIKit
class NavigationBarSetUp: UINavigationItem {
override func awakeFromNib() {
super.awakeFromNib()
let currentstoryboard = UIStoryboard()
let screenWidth = UIScreen.main.bounds.width
let storyboard1 = UIStoryboard(name: "First", bundle: nil)
//let storyboard2 = UIStoryboard(name: "Second", bundle: nil)
//let storyboard3 = UIStoryboard(name: "Third", bundle: nil)
//Current title
self.title = nil
if currentstoryboard == storyboard1 && (screenWidth == 320) {
self.title = " diet 1"
print ("called short title")
} else if currentstoryboard == storyboard1 && (screenWidth > 320) {
// rest of screen sizes
self.title = " Welcome to diet 1"
print ("called full title")
}
// Repeat if statement for storyboards 2 & 3 with different titles.
// Rest of Class code - Bar Button Item Setup
self.hidesBackButton = false
self.leftItemsSupplementBackButton = true
// Left Side Button Setup
let buttonView = UIToolbar()
buttonView.frame = .init(x: 0, y:-7, width: 30, height: 30)
// Setting UIToolbar Transparency of the toolbar
buttonView.setBackgroundImage(UIImage(),
forToolbarPosition: .any,
barMetrics: .default)
buttonView.setShadowImage(UIImage(), forToolbarPosition: .any)
// This is a UIView the Toolbar will sit inside which will then be placed into the Navigationbar.
let navigationContainer = UIView()
navigationContainer.frame = .init(x: 0, y:0, width: 30, height: 30)
// ButtonBarItems Set Up
let ModalButton = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(NotesButtonClicked))
let negativeSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: self, action: nil)
negativeSpace.width = -10
//Add ButtonBarItems into the UIToolbar ButtonView
buttonView.setItems([negativeSpace, ModalButton], animated: false)
// Add UItoolbar into UIView
navigationContainer.addSubview(buttonView)
//Icon Size to fit
buttonView.sizeToFit()
//Convert UIView into Barbutton Item to set in the Navigation Bar
let topLeft = UIBarButtonItem()
topLeft.customView = navigationContainer
self.setLeftBarButton(topLeft, animated: false)
// Setup of the Right Handside Menu Button
let BurgerButton = UIButton()
BurgerButton.frame = .init(x: -1, y: 0.5, width: 62, height: 25)
BurgerButton.setBackgroundImage(UIImage(named: "BurgerButton1.pdf"), for: .normal)
BurgerButton.addTarget(self, action: #selector(MenuClicked), for: .touchUpInside)
let topRight = UIBarButtonItem()
topRight.customView = BurgerButton
self.setRightBarButton(topRight, animated: true)
}
// Calls the Left Button Action.
func NotesButtonClicked(_ sender: UIBarButtonItem) {
print("Notes Modal Is Called")
//Code here
}
// Calls the Right Button Action.
func MenuClicked(_ sender: UIButton) {
print("Menu is Opened - Rightside")
//Code here
}
}
Well, you are doing a couple things that won't work:
let currentstoryboard = UIStoryboard()
You just created a NEW instance of a (empty) UIStoryBoard object...
let storyboard1 = UIStoryboard(name: "First", bundle: nil)
You just created a NEW instance of a UIStoryBoard object, referencing the Storyboard named "First" (assuming it exists in your app).
Those two instances could never be equal.
UIViewController has a .storyboard property, which is "The storyboard from which the view controller originated."
However, even if you tried:
let currentstoryboard = self.storyboard
let storyboard1 = UIStoryboard(name: "First", bundle: nil)
if currentstoryboard == storyboard1 { ... }
They will still never be equal, because storyboard1 is a new instance.
You might try:
let sbName = self.storyboard?.value(forKey: "name") as? String
if sbName == "First" { ... }
Unfortunately, that does not seem to be documented by Apple, and may very possibly and up getting your app rejected.
I'd think you would be much better off using your own variables / properties to keep track of what's what.
I have using EKEventViewController in our app.
Code should like below
class MyEkEventViewController: EKEventViewController {
override func viewDidLoad() {
super.viewDidLoad()
let cancelButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.cancel, target: self, action: #selector(MyEkEventViewController.cancel))
self.navigationController?.navigationItem.setLeftBarButton(cancelButton, animated: false)
//self.navigationController?.navigationItem.leftBarButtonItem = cancelButton
}
}
#objc fileprivate func cancel() {
_ = navigationController?.popViewController(animated: true)
}
}
# My invocation
.
.
.
let eventViewController = MyEkEventViewController()
eventViewController.delegate = self
eventViewController.allowsEditing = true
eventViewController.allowsCalendarPreview = true
eventViewController.hidesBottomBarWhenPushed = true
eventViewController.event = event
self.navigationController?.pushViewController(eventViewController, animated: true)
Back arrow only displayed. But Cancel button is not displayed in left side navigation bar.