Add dismiss button to Bottom Sheet - ios

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)
}

Related

(Swift) Navigation bar is hidden in viewController

I want to present SecondVC from FirstVC and make SecondVC have a rightBarButtonItem called Close which calls an #objc function which dismisses SecondVC.
Also, I want to change secondVC's title from firstVC:
This is how I present SecondVC from the FirstVC:
let secondVC = AdviceDetailsViewController()
secondVC.modalPresentationStyle = .fullScreen
secondVC.title = "Example" //Value of type 'UINavigationController' has no member 'myTitle'
self.present(secondVC, animated: true)
Code for navigationBar in secondVC:
public var myTitle: String = ""
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .gray
self.title = myTitle
self.navigationController?.navigationBar.barTintColor = UIColor.orange
self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Close", style: .plain, target: self, action: #selector(closeDetails))
}
#objc func closeDetails() {
self.dismiss(animated: true, completion: nil)
}
No Navigation bar is visible in secondVC, the only visible thing is gray background color.
What should I change? I am doing everything programmatically in this app.
Use this method to show second VC
let nc = UINavigationController(rootViewController: AdviceDetailsViewController())
nc.modalPresentationStyle = . fullScreen
self.present(nc, animated: true)
Regarding your Title issue,
Value of type 'UINavigationController' has no member 'myTitle' Yes its true, because we define myTitle variable on SecondVC,So we assign myTitle like this
let vc = SecondViewController()
vc.myTitle = "My Title"
let nc = UINavigationController(rootViewController: vc)
nc.modalPresentationStyle = . fullScreen
self.present(nc, animated: true)

CNContactViewController navigation bar colour not working properly

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

How to make a transparent background of Popup ViewController?

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

IOS Swift Programmatically created navigationController TOOLBAR (bottom bar) item actions not working

I am having trouble creating a UINavigationController toolbar programmatically. I have previously used storyboards to do this successfully but would like to try doing it all in code.
I have created the UIBarButtonItems programmatically, but the actual functions or actions they are supposed to perform when pressed are not working.
To clarify, I am NOT attempting to add UIBarButtonItems to the top bar. I've seen dozens of questions all asking the same thing. I am referring to the toolbar at the bottom that comes with the UINavigationController. This means no "rightBarButtonItem" or "leftBarButtonItem"
Here is the code:
class ProgOneViewController: UIViewController {
var chatRoomsButton: UIBarButtonItem = {
var button = UIBarButtonItem(title: "Chats", style: .plain, target: self, action: #selector(segueToChatRoomController(_:)))
return button
}()
var exploreButton: UIBarButtonItem = {
var button = UIBarButtonItem(title: "Explore", style: .plain, target: self, action: #selector(segueToExploreController(_:)))
return button
}()
var profileButton: UIBarButtonItem = {
var button = UIBarButtonItem(title: "Profile", style: .plain, target: self, action: #selector(segueToProfileController(_:)))
return button
}()
// Flexible spaces that are added in between each button.
var flexibleSpace1: UIBarButtonItem = {
var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
return flexibleSpace
}()
var flexibleSpace2: UIBarButtonItem = {
var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
return flexibleSpace
}()
var flexibleSpace3: UIBarButtonItem = {
var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
return flexibleSpace
}()
var flexibleSpace4: UIBarButtonItem = {
var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
return flexibleSpace
}()
// These are the functions that are not being called for some mysterious reason.
func segueToChatRoomController(_ sender: Any) {
print("segueing to chat rooms controller")
let chatRoomsController = ChatRoomsViewController()
let navController = UINavigationController(rootViewController: chatRoomsController)
self.present(navController, animated: false, completion: nil)
}
func segueToExploreController(_ sender: Any) {
print("segueing to explore controller")
let exploreController = ExploreCollectionViewController()
let navController = UINavigationController(rootViewController: exploreController)
self.present(navController, animated: false, completion: nil)
}
func segueToProfileController(_ sender: Any) {
print("segueing to profile controller")
let profileController = ProfileTableViewController()
let navController = UINavigationController(rootViewController: profileController)
self.present(navController, animated: false, completion: nil)
}
func setUpToolbar() {
print("setting up toolbar")
self.navigationController?.setToolbarHidden(false, animated: false)
self.navigationController?.toolbar.isUserInteractionEnabled = true
let toolBarItems = [flexibleSpace1, chatRoomsButton, flexibleSpace2, exploreButton, flexibleSpace3, profileButton, flexibleSpace4]
self.setToolbarItems(toolBarItems, animated: true)
// For some reason, these two methods leave the toolbar empty.
//self.navigationController?.setToolbarItems(toolBarItems, animated: true)
//self.navigationController?.toolbar.items = toolBarItems
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
setUpToolbar()
}
}
EDIT*
Here is the code used to instantiate the ProgOneViewController inside a UINavigationController
func pushToTestProgrammaticallyCreatedViews() {
let progOneViewController = ProgOneViewController()
let navController = UINavigationController(rootViewController: progOneViewController)
//navController.isToolbarHidden = false
//progOneViewController.setUpToolbar()
self.present(navController, animated: false, completion: nil)
}
I called this function upon clicking a button in my storyboard-created view controller. The function signature was long in order to specify which viewControllers were tests (created programmatically) :)
first of all you have to make sure that your ProgOneViewController is really included in a UINavigationController. if that is the case the toolbar as well as the barbuttonitems are shown (tried your code in my project).
except of that you have to change all of your barbuttonitem declarations to lazy var so that the references to self within the declarations point to the viewcontroller and target-action works.
feel free to ask if there are any questions :)

In EKEventViewController Edit button in two place with same functionality

Both Edit button is behaving in same manner. So I want to remove one edit button . How can i achieve it?
//*****my code is here:
var eventDetail = EKEventViewController()
eventDetail.event = selectedEvent
eventDetail.allowsEditing = true
eventDetail.allowsCalendarPreview = true
eventDetail.delegate = self
var navController = UINavigationController(rootViewController:eventDetail) presentViewController(navController, animated: true, completion: nil)
It can be done by removing it twice:
presentViewController(navController, animated: true) {
eventDetail.navigationItem.leftBarButtonItem = nil
}
/////////////////
class EventViewController: EKEventViewController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
navigationItem.leftBarButtonItem = nil
}
}

Resources