I'm having a problem with presenting an alert. I'm using UIAlertController. When the user presses the submit button, an alert needs to be presented immediately saying "Please Wait.." while the app does some operations. The alert is dismissed after the operations are complete. I'm having a long delay (several seconds) before the alert is presented even though the alert is supposed to be presented before i even start doing the operations. I tried dispatch async and tried using closures and nothing is working..still a delay of several seconds before alert is presented.
How do i make it so that the alert is presented immediately after the button the pressed?
override func viewDidLoad() {
super.viewDidLoad()
submitButton.addTarget(self,action:#selector(buttonAction),for:.touchUpInside)
}
#objc func buttonAction(){
waiting()
doOperations()
}
func waiting(){
DispatchQueue.main.async{
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .alert)
let loadingIndicator = UIActivityIndicatorView(frame: CGRect(x: 10, y: 5, width: 50, height: 50))
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.gray
loadingIndicator.startAnimating()
alert.view.addSubview(loadingIndicator)
self.present(alert, animated: false, completion: nil)
}
}
func doOperations(){
...
}
func dismissWaiting{
...
//dismiss alert
}
Just dispatch to main thread the alert.
Hey I resolved the problem just by putting the call to doOperations in the completion of the presentation of the alert. Like this:
self.present(alert, animated: false, completion: {self.doOperations()})
Now the alert is presented instantly after button press and everything works fine. Thanks guys for all the suggestions.
Related
Hello everyone I got weired bug which I can't solve - I dig over the internet and couldn't find any solution.
I got a viewcontroller screen with 6 buttons on it. I want to show the user a UIAlertview with a description text any time when clicks on one of those buttons.
The problem is that in the first button I got the text right but the problem begins from the second button and so on.
The new UIAlertview shows the new description text together with the old text so the new text can't be read.
From the debuger I found that the old UIAlertview are there but just not shown on the main screen.
What is the right way to remove it from the view controller?
This is my dismiss function:
#objc func dismissAlert() {
guard let targetView = mytargetView else {
return
}
UIView.animate(withDuration: 0.25, animations: {self.alertView.frame = CGRect(x: 40, y: targetView.frame.size.height, width: targetView.frame.size.width-80, height: 300)}, completion: {done in
if done {
UIView.animate(withDuration: 0.25, animations: {
self.backgroundView.alpha = 0
}, completion: { done in
if done {
self.alertView.removeFromSuperview()
self.backgroundView.removeFromSuperview()
}
})
}
})
}
The dismissAlert method is not the proper way to dismiss an alert view. You can simply call the dismiss method on any alert view to properly dismiss it.
let alert = UIAlertController(title: "Some Title", message: "Some message", preferredStyle: .alert)
// Presenting an alert
present(alert, animated: true, completion: nil)
// Dismissing an alert
alert.dismiss(animated: true, completion: nil)
I recently started having an issue where the popover controller will some times show up on the wrong corner. When it works correctly, the popover source is a button on the upper right corner. This is what happens most o the time. Now, when I land on this page "too quickly" from a specific route, the popover shows up on the upper left corner.
Another thing that is weird is that when loading is artificially delayed (like when I set break points for debugging) the popover shows up correctly.
Since it seemed to be a timing issue, I tried moving the navigation configuration from viewDidLoad to viewDidAppear, but this didn't work.
This function is called from viewDidLoad:
func configureNav() {
if canAddDoc == true {
let customButton = UIButton(type: .system)
customButton.setImage(with: .add, tintColor: UIColor.white, imageEdgeInsets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
customButton.addTarget(self, action: #selector(showAddDocSheet), for: .touchUpInside)
addButton = UIBarButtonItem(customView: customButton)
}
shareButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.action,
target: self,
action: #selector(shareButtonPressed))
navigationItem.rightBarButtonItems = (addButton == nil) ? [shareButton!] : [shareButton!, addButton!]
#objc func showAddDocSheet() {
guard let addButton = addButton else { return }
self.displayActionSheet(sourceButton: addButton)
}
}
func displayActionSheet(sourceButton: UIBarButtonItem) {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
//Action sheet code goes here
if let popoverController = actionSheet.popoverPresentationController {
popoverController.barButtonItem = sourceButton
popoverController.sourceView = sourceButton.customView
popoverController.permittedArrowDirections = .up
}
self.present(actionSheet, animated: true, completion: nil)
}
This may sound a weird solution but something similar happened to me before and it got solved when setting the animation to false while presenting the VC ,
self.present(actionSheet, animated: false, completion: nil)
Every time a button is pressed, I am trying to present another view controller on top of it. I used this answer, and it works when I press the button for the 1st time. However, when I press the button for the 2nd/3rd/etc. time, the view controller does not appear and the print statement does not print either. Any help would be greatly appreciated!
Here is my code:
#IBAction func myButtonPressed(_ sender: Any) {
print("button pressed")
var vc = storyboard!.instantiateViewController(withIdentifier: "myIdentifier") as! secondViewController
var transparentGrey=UIColor(red: 0.26, green: 0.26, blue: 0.26, alpha: 0.90)
vc.view.backgroundColor = transparentGrey
vc.modalPresentationStyle = .overCurrentContext
present(vc, animated: true, completion: nil)
}
EDIT: The above code works as long as you dismiss the secondViewController correctly after the button was first pressed. I put this code in the secondViewController and it worked for me:
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
So i have a viewcontroller which is basically an alert window which is supposed to be a popup and be dismissed by the tap on outside its frame.
But whenever i call that VC, it is always displayed as fullscreen and not as a pop up window.
I have tried a couple of ways to do this, namely as mentioned below.
if let exp : String = expiredVehicles[i] {
expiredVehicleNumber = expiredVehicles[i]
let popUpVC = SubscriptionExpired()
popUpVC.modalTransitionStyle = .crossDissolve
popUpVC.modalPresentationStyle = .popover // also tried other presentation styles but none work and it is still fullscreen
popUpVC.view.backgroundColor = UIColor.white.withAlphaComponent(0.8)
self.present(popUpVC, animated: true, completion: nil)
}
in case anyone need to see the definition of that VC, i will be glad to share it
i feel i should mention that the VC to be displayed as a popup is inheriting UIViewController
Any insight that might help would be great.
Thanks for the input
One potential way is to add a tap gesture recognizer to your View, which dismisses the VC.
But this will only be helpful if this popup has read-only info and doesn't require any further action from the user.
func addTapRecognizer(){
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap))
self.view.addGestureRecognizer(tap)
}
#objc func handleTap(){
// dismiss the VC here
}
}
You can call following method to show popup:
let popupVC = SubscriptionExpired()
popupVC.modalPresentationStyle = .overCurrentContext
self.addChild(popupVC)
popupVC.view.frame = self.view.frame
self.view.addSubview(popupVC.view)
popupVC.didMove(toParent: self)
}
Then, for removing that popup you can use:
UIView.animate(withDuration: 0.25, animations: {
self.view.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.view.alpha = 0.0
}, completion: { (finished) in
if finished {
self.view.removeFromSuperview()
}
})
In that case I have a button inside popup and whenever that button pressed above method triggers. Can you please try it? I can edit my answer according to your needs.
You need to implement this in you presenting view controller:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .none
}
UIPopoverPresentationController displaying popover as full screen
I am trying to get a UIAlterController to display (as soon as the scene is set up) with the following buttons:
Accept - won't do anything, just close the UIAlertController
Leave to Menu - should transition to the MenuScene
My code looks as follows (I put the alert controller inside an action so it first displays the scene and after 0.5 seconds it should start displaying the alert):
//make action
var actionBlock = SKAction.runBlock({
//alert controller
var alert = UIAlertController(title: "Welcome", message: "Are you sure you want to proceed?", preferredStyle: UIAlertControllerStyle.Alert)
//action with no handler
var acceptAction = UIAlertAction(title: "Yes", style: UIAlertActionStyle.Cancel, handler: nil)
//action thats supposed to transition to MenuScene (AFTER BEING TAPPED!!)
var leaveAction = UIAlertAction(title: "Back to Menu", style: UIAlertActionStyle.Destructive, handler: {_ in self.backToMenu()})
//add action to the alert controller
alert.addAction(acceptAction)
alert.addAction(leaveAction)
//add alert controller to view
self.view?.window?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
}
//wait for 0.5s action
var wait = SKAction.waitForDuration(0.5)
//run the action
self.runAction(SKAction.sequence([wait, actionBlock]))
and I placed it right into the DidMoveToView function. When I run the code, it immediately transitions back to the MenuScene without even waiting for the user to tap either one of the actions, and then the alert is still on the screen (but on the MenuScene).
I am really confused and I've been on this for several hours but I just can't figure out what my mistake is, and how to make it work..
Anybody help please? Any code that works would be really appreciated!!!