How to popup and dismiss a view in swift 5 - ios

I have created .xib files and connected them with appropriate view controllers. Unfortunately, it doesn't go well.
I have checked and tried so many examples, but not working for newest version. Using Xcode 11.3 and iOS 13.
here is the code I have tried.
TopView.swift
#IBAction func btnConnectTapped(_ sender: Any) {
print("tapped")
var listVC: PopupView // This one is UIView and popped the window
listVC = Bundle.main.loadNibNamed("PopupView", owner: self, options: nil)?.first as! PopupView
self.view.addSubview(listVC)
// Tried for the UIViewController and not worked
/*let VC = ScanViewController(nibName: "ScanViewController", bundle: nil)
//self.present(VC, animated: true, completion: nil)
self.navigationController?.pushViewController(VC, animated: true)*/
}
Popup.swift // dismiss the popped view
#IBAction func btnCancelTapped(_ sender: Any) {
DispatchQueue.main.async {
self.removeFromSuperview()
}
}
both ScanViewController and Popup view have same purpose.
Can someone help me

pod Url: https://github.com/Orderella/PopupDialog
eg to make Popup:
let ratingVC = TimeSelection(nibName: "TimeSelection", bundle: nil)
ratingVC.view.backgroundColor = .white
ratingVC.delegate = self
let popup = PopupDialog(viewController: ratingVC,
buttonAlignment: .horizontal,
transitionStyle: .bounceDown,
tapGestureDismissal: true,
panGestureDismissal: true)
popup.popupContainerView.backgroundColor = .clear
present(popup, animated: true, completion: nil)

TopView.swift
#IBAction func btnTap(_ sender: UIButton)
{
if PopupScreensharedInstance != nil
{
PopupScreensharedInstance.makeInstanceNil()
}
view.addSubview(popView.SharedInstance())
}
popView.swift
var PopupScreensharedInstance : popView! = nil
class popView: UIView {
class func SharedInstance() ->popView
{
if(PopupScreensharedInstance == nil)
{
PopupScreensharedInstance = (Bundle.main.loadNibNamed("popView", owner: self, options: nil)![0] as! popView)
PopupScreensharedInstance.frame = UIScreen.main.bounds
}
return PopupScreensharedInstance
}
func makeInstanceNil()
{
PopupScreensharedInstance = nil
self.removeFromSuperview()
}
#IBAction func cancle(_ sender: UIButton)
{
makeInstanceNil()
}
}

Related

swift ios UIButton inside UIView not working

I made it using a storyboard
I made another view controller for the custom tab bar and created a UIView called innerContents.
And I made another view controller for the setting page in it and put another view controller in innerContents with addSubview.
CustomTabBar with innerContents UIView
thats innerTabBar main CustomTabBar View Controller page
other ViewController
i will put thats ViewController in innerContents. so i writed addSubView. they are showing but UIButtons are not working. only work ScrollView.
How can I fix it?
code
I confirmed that all outlets are connected normally.
But the UIButton inside the UIView inside the UIScrollView inside the UiView of another view controller inside the UiView doesn't work.
mainCustomTabBar Page viewController > innerContents > otherViewController(addSubView) > UIView > UI ScrollView > UIView > UIView > UIButton(it's not working. i want fix that)
if currentPage != 5 {
currentPage = 5
print("탭바 클릭 5")
guard let AppSet = self.storyboard?.instantiateViewController(identifier: "AppSetViewController") as? AppSetViewController else {return}
AppSet.view.frame = ContentsView.bounds
AppSet.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
AppSet.view.tag = 500
removeSubview(tag: nowTag)
nowTag = 500
ContentsView.addSubview(AppSet.view)
let root = UIApplication.shared.windows.first?.rootViewController
root?.addChild(AppSet)
AppSet.didMove(toParent: root!)
page5Mode()
return
}
}
//
// AppSetViewController.swift
// rael
//
// Created by HongDaehyeon on 2021/07/08.
// 앱 설정 페이지를 위한 페이지 입니다.
import UIKit
class AppSetViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBOutlet var ContentView: UIView!{
didSet {
self.ContentView.isUserInteractionEnabled = true
}
}
#IBOutlet var Scrollview: UIScrollView!{
didSet{
self.Scrollview.isExclusiveTouch = true
}
}
//지갑정보
#IBAction func walletInfo(_ sender: Any) {
print("지갑정보")
}
//알림설정
#IBAction func alertSet(_ sender: Any) {
print("알림설정")
}
//인증방식설정
#IBAction func authSet(_ sender: Any) {
print("인증방식설정")
}
//공지사항
#IBAction func noticeNav(_ sender: Any) {
let vc = self.storyboard?.instantiateViewController(identifier: "SettingsNoticeViewController")
let navController = UINavigationController(rootViewController: vc!)
navController.modalPresentationStyle = .fullScreen
navController.modalTransitionStyle = .crossDissolve
navController.setNavigationBarHidden(true, animated: false)
self.present(navController, animated: true, completion: nil)
}
//FAQ
#IBAction func faqNav(_ sender: Any) {
let vc = self.storyboard?.instantiateViewController(identifier: "FaqViewController")
let navController = UINavigationController(rootViewController: vc!)
navController.modalPresentationStyle = .fullScreen
navController.modalTransitionStyle = .crossDissolve
navController.setNavigationBarHidden(true, animated: false)
self.present(navController, animated: true, completion: nil)
}
//고객상담
#IBAction func serviceCenter(_ sender: Any) {
print("고객상담")
}
//약관 및 정책
#IBAction func termsNav(_ sender: Any) {
print("약관 및 정책")
}
//지갑 삭제
#IBAction func removeWallet(_ sender: Any) {
print("지갑삭제")
}
//전화걸기
#IBAction func callService(_ sender: Any) {
print("전화걸기")
let urlString = "tel://1588-8282"
let numberURL = NSURL(string: urlString)
UIApplication.shared.open(numberURL! as URL, options: [:], completionHandler: nil)
}
//앱정보 로딩
#IBOutlet var appVer: UILabel!{
didSet{
self.appVer.text = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String
}
}
}```

How to reload present view controller swift?

I have two Present view controllers. The thing i want to do is when the second Present view controller is dismissed it will automatically reload the first present view controller(Table view). note: first view controller holds a table view, basically i want to reload the table view of first controller.
ViewWillAppear code:
override func viewWillAppear(_ animated: Bool) {
tableViewReloadFromCreateProductVC()
}
func tableViewReloadFromCreateProductVC () {
tableView.reloadData()
}
Calling from second view controller code:
SecondViewController.tableViewReloadFromCreateProductVC()
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
FirstViewController calling 2nd view controller
#IBAction func CallSecondViewButton(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: true, completion: nil)
}
just write the code in viewWillAppear() method of the view controller that you want to reload like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
//perform api call if any
yourTableView.reloadData()
}
2nd view controller
#IBAction func CloseButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
after dissmissing the viewWillAppear method of firstViewController will autometically called.
The First two snippets are for first view controller and the last one is for second view controller
Reloading the entire table view could sometimes be costly and it also sounds like you're making an API call as well so unless you want your table view to be reloaded and the API call made every time the view controller becomes visible whether or not you've made changes to it, you want the reloading to be done only when it's necessary.
You can try it in a few different ways:
class CreateProductVC: UITableViewController {
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
}
class SecondViewController: UIViewController {
weak var delegate: CreateProductVC?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
self.delegate?.tableView.reloadData()
}
}
}
or
class CreateProductVC: UITableViewController {
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.isDismissed = { [weak self] in
self?.tableView.reloadData()
}
present(secondVC, animated: true, completion: nil)
}
}
}
class SecondViewController: UIViewController {
var isDismissed: (() -> Void)?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
self.isDismissed?()
}
}
}
or if you want more fine-grained control over what to do with the new data:
protocol ReloadVC {
func reload(_ value: String)
}
class CreateProductVC: UITableViewController, ReloadVC {
var dataSource: [String]! {
didSet {
tableView.reloadData()
}
}
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
func reload(_ value: String) {
dataSource.append(value)
}
}
class SecondViewController: UIViewController {
var delegate: ReloadVC?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
let someValue = "Some Value"
self.delegate?.reload(someValue)
}
}
}

How to dismiss the current ViewController and change to the new ViewController in Swift?

I am new to iOS swift. I have three ViewController.
The page-A is root controller and it will present to the page-B. It has a timer in page-B. After 5 sec, it will change View from page-B to page-C , and close the page-B at the same time.
In the ViewControll-B
class AViewController: UIViewController {
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
//set the timer , and chagne view to C ViewController
Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.changeToAnswerView),
userInfo: nil,
repeats: false)
}
#objc func changeToAnswerView() {
dismissLoader()
}
func dismissLoader() {
dismiss(animated: true) {
print("Dismissing Loader view Controller")
}
}
override func viewWillDisappear(_ animated: Bool) {
//change view to Answer ViewController
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
self.present(filterVC, animated: true, completion: nil)
}
}
After timer execute for 5 sec , the BViewController will dismiss itself and present to the BViewController.
But the following error will happened:
whose view is not in the window hierarchy
Did I missing something?
Question:
How to dismiss the current ViewController and change to the new ViewController in Swift?
Thanks in advance.
Here is the Working code that you can Try
Your Controller which is Dismissed and Tend to make a new controller being presented
import UIKit
class pdfVC: UIViewController
{
var timer : Timer?
override func viewDidLoad()
{
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(pdfVC.timerAction), userInfo: nil, repeats: false)
}
#objc func timerAction()
{
if timer != nil {
timer?.invalidate()
dismiss(animated: true, completion: {
print("Dismissed")
})
}
}
override func viewWillDisappear(_ animated: Bool) {
if self.isBeingDismissed {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "demoViewController")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
print("called")
self.presentingViewController?.present(filterVC, animated: true, completion: nil)
}
}
}
Output
Try changing dismissLoader function to something like:
func dismissLoader() {
dismiss(animated: true) {
print("Dismissing Loader view Controller")
if let presentingController = self.presentingViewController {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
presentingController.present(filterVC, animated: true, completion: nil)
}
}
}
and remove the viewWillDisappear function.
The problem is that you are trying to present the BViewController from the loader after being dismissed (i.e removed from window hierarchy) which at that point doesn't exist.
So, the solution is that you could get a reference to the presenting view controller which is presenting the loader and which will appear after dismissing the loader and present the new view controller from there.
in your B view controller after its dismissed,
in its completion handler
self.dismiss(animated: true) {
if let presentingVC = self.presentingViewController {
present c view controller here
}
}
this above is one way to do so, another way is, through delegate
in A view controller:
if let bVC = self.storyboard.instantiateViewController(withIdentifier: B.controllerIdentifier) as? B {
bVC.delegate = self
self.present(bVC, animated: true, completion: nil)
}
inside B View Controller
add delegate method for Protocol
protocol BProtocol: class {
func didClose()
}
and in B dismiss
var delegate: BProtocol?
self.dismiss(animated: true) {
self.delegate?.didClose()
}
this delegate will be implemented by A ViewController as
extension AViewController: BProtocol {
func didClose() {
//present C
}
}
You are trying use a reference (instance) of view controller, that would no longer exist in memory.
Try this
if let presentingVC = self.presentingViewController {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
presentingVC.present(filterVC, animated: true, completion: nil)
}
Note: Present a new view controller (filterVC) once your current view controller is dismissed. A view controller can present only a one view controller at time (if you choose present modally). Perform this operation after a delay of 1 second..
Edit
Try with this edited code.
Class AViewController: UIViewController {
var timer: Timer?
var presentingVC: UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
//set the timer , and chagne view to C ViewController
Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.changeToAnswerView),
userInfo: nil,
repeats: false)
}
#objc func changeToAnswerView() {
dismissLoader()
}
func dismissLoader() {
dismiss(animated: true) {
print("Dismissing Loader view Controller")
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//change view to Answer ViewController
if let presentingVC = self.presentingViewController {
self.presentingVC = presentingVC
}
}
override func viewWillDisappear(_ animated: Bool) {
//change view to Answer ViewController
super.viewWillDisappear(animated)
if let presentingVC = self.presentingVC {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
presentingVC?.present(filterVC, animated: true, completion: nil)
} else {
print("Presenting View controller is nil")
}
}
}

How to present some VC at modalVC's parent VC without hierarchy warnings?

I try to present VCs but buttons in popover menu, but I have hierarchy warnings like this:
Warning: Attempt to present "UIViewController: 0x14def7500" on "MyProject.MainViewController: 0x14f976400" whose view is not in the window hierarchy!
I have MainViewController and PopupMenu VCs classes:
Swift 4.0
class MainViewController: UIViewController, UIPopoverPresentationControllerDelegate {
//... here is my VC code
// showing Popup Menu VC
#IBAction func showPopupMenu(sender: UIButton) {
menuVC = PopupMenu()
menuVC?.modalPresentationStyle = .popover
menuVC?.preferredContentSize = CGSize(width: 150, height: 250)
if let pvc = menuVC?.popoverPresentationController {
pvc.permittedArrowDirections = .up
pvc.delegate = self
pvc.sourceView = sender
pvc.sourceRect = sender.bounds
}
self.present(menuVC!, animated: true, completion: nil)
}
// showing VC from popupMenu VC
#IBAction func showVCFromPopup(from target: PopupMenu, vc: UIViewController) {
target.dismiss(animated: false, completion: nil) // dismiss popup
if target.isBeingDismissed { // check is popup dismissed
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil)
}
}
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
}// end of class
class PopupMenu: UIViewController {
var button = UIButton()
// here is init's
override func viewDidLoad() {
//... some other code
button.addTarget(self, action: #selector(vcOpen(sender:)), for: .touchUpInside)
}
#IBAction func vcOpen(sender: UIButton) {
if sender == button {
let vc = UIViewController()
if parent != nil { print("PARENT")} // Never will work, no ideas why, so MainVC isn't a parent of PopupMenu
if let mainVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "MainViewController") as? MainViewController {
print("# ACTION: Opening VC")
mainVC.showVCFromPopup(target: self, as: vc!) // opening VC
}
}
}
}
But I have warning.
Maybe anyone will find mistakes in my code or have any ideas how to do this.
Thanks for all answers!
I edited you code to pass a reference of the mainVC to the PopupMenu:
class MainViewController: UIViewController, UIPopoverPresentationControllerDelegate {
// showing Popup Menu VC
#IBAction func showPopupMenu(sender: UIButton) {
menuVC = PopupMenu()
menuVC?.modalPresentationStyle = .popover
menuVC?.preferredContentSize = CGSize(width: 150, height: 250)
menuVC?.MainVC = self <--- here
if let pvc = menuVC?.popoverPresentationController {
pvc.permittedArrowDirections = .up
pvc.delegate = self
pvc.sourceView = sender
pvc.sourceRect = sender.bounds
}
self.present(menuVC!, animated: true, completion: nil)
}
}
class PopupMenu: UIViewController {
var mainVC: UIViewController <-- here
#IBAction func vcOpen(sender: UIButton) {
if sender == button {
mainVC.showVCFromPopup(target: self, as: vc!) <-- here
}
}
}

Black Flickering while Dismissing PopOverViewController

I'm getting black flickering screen while dismissing PopOverViewController.
Code in ViewController.swift
if segue.identifier == "addComment"
{
let controller = segue.destinationViewController as! ProfileCommentPopOver
controller.popoverPresentationController?.delegate = self
controller.preferredContentSize = CGSizeMake(250, 150)
controller.fetchedProfileID = sendToUserID
}
PopOverViewController.swift
#IBAction func addCommentAction(sender: UIButton)
{
self.dismissViewControllerAnimated(true, completion: nil)
}
try
#IBAction func addCommentAction(sender: UIButton)
{
self.dismiss(animated: true, completion:{})
}

Resources