In this drag and drop game (adapted from this tutorial), the player has to match the label to the right target. I have it set so that if the touch ends and the label's center is inside the target, it is removed from the screen and the game starts over.
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if label.name == "letters" {
if lettersBin.frame.contains(label.position) {
// remove it and create a new label
label.removeFromParent()
setupDragLabel()
However, I want to trigger a notification if the player drops the wrong label onto the bin, so:
else if label.name == "numbers" {
if lettersBin.contains(label.position) ...
What would I write to finish this? Do I make another label appear on the screen?
It might be easiest to use a UIAlertController. You can add the messages along with button actions to display that the user was wrong.
let converterAction = UIAlertController(title: "Your title here", message: "Your message to the user here", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default){ _ in
//Any custom action to happen here
}
converterAction.addAction(okAction)
present(converterAction, animated: true, completion: nil)
If you do not want to show an alert, you can do the following:
Add a label to the Storyboard and to your file.
Set that label to be hidden by default.
Programatically set label.isHidden = false and set it's text as you wish.
What I now labeled "label" can be anything though, you could even create a group of views and hide/show them all at once. Useful when wanting to show a Progress Indicator and a "Loading..." Label at the same time.
Related
I have a navigation bar with two buttons as the right bar button items and a text field in the title view. If I tap the text field, a search screen pops up and I can enter texts into the text field. The texts in the text field would set the "resultText" variable in my code below. The button items, including filterItem and mapItem, are well connected with #IBOutlet.
I would like to hide the right bar button items when the text field is not empty. With the code shown below, it works fine initially when I enter texts into the text field. However, when I delete the texts in the text field and then returns from the pop-up, the app crashes because the button items are found nil. I do not understand why it is nil. Am I missing something here?
if !resultText.isEmpty {
navigationItem.rightBarButtonItem = nil
} else {
navigationItem.setRightBarButtonItems([filterItem, mapItem], animated: false)
}
You are adding and removing buttons from the navigation bar, it must be removing reference from view. Try adding it using code -
func addBarButtonItems() {
let filterItemBarButton = UIBarButtonItem(title: "filterItem", style: .plain, target: self, action: #selector(filterItemTapped))
let mapItemBarButton = UIBarButtonItem(title: "mapItem", style: .plain, target: self, action: #selector(mapItemTapped))
navigationItem.rightBarButtonItems = [filterItemTapped, mapItemTapped]
}
func removeBarButtonItems() {
navigationItem.rightBarButtonItems = nil
}
#objc private func filterItemTapped() {
//code
}
#objc private func mapItemTapped() {
//code
}
Call these methods correctly in textField delegate methods.
func showAlert(...) {
let alertController = UIAlertController(...)
let add = UIAlertAction(title: "Add", style: .default) { (action) in
onAdd?()
}
alertController.addAction(ok)
...
}
I would like to keep the popup alert after click on Add. But it seem iOS will auto close the popup. How to make it work?
The only way to prevent a UIAlertController's alert from being dismissed when a button is tapped is to disable the button.
If you don't like that, don't use UIAlertController; use your own presented view controller. That's all a UIAlertController is, after all. So it's easy to write your own if you need to.
I'd like to create a very common effect as in the picture below :
Explanation : the effect I'd like to accomplish consists in a view that appears (slides in) at the bottom of the screen when user clicks a button : you can still see the screen behind this view, but it applies a "dark layer" (black view with let's say 60% opacity) on the top of it. When user clicks on Block or Report absue (as for this example) it would perform the respective actions. Now when user clicks on cancel, and also when he clicks anywhere on the "dark layer" it would bring him back to the screen.
What I tried : presenting a new view controller (but it would use more data than necessary), using a overlay layer but I even didnt get close to that effect that we're usually seeing on apps. I'm not sure but I'd say that the best way to get that effect is using views ?
Does anyone have an idea please ?
Thanks and have a good day,
J
You are looking for a native element called UIActionSheet. It has become the part of UIAlertController, and does exactly what you are looking for.
Here is a little help how to set up one:
// Create you actionsheet - preferredStyle: .actionSheet
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
// Create your actions - take a look at different style attributes
let reportAction = UIAlertAction(title: "Report abuse", style: .default) { (action) in
// observe it in the buttons block, what button has been pressed
print("didPress report abuse")
}
let blockAction = UIAlertAction(title: "Block", style: .destructive) { (action) in
print("didPress block")
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
print("didPress cancel")
}
// Add the actions to your actionSheet
actionSheet.addAction(reportAction)
actionSheet.addAction(blockAction)
actionSheet.addAction(cancelAction)
// Present the controller
self.present(actionSheet, animated: true, completion: nil)
It should produce the following output:
I just made a simple app where you type things in four boxes and can randomly select one. After typing in the boxes I need the keyboard to go away so people can see what the result is, but the on-screen keyboard just stays. Is this something I need to change in the files of the app?
You have to use resignFirstResponder() property of the text field.
If you want to hide the keyboard when a tap occurred outside the text field,
you can use an UITapGestureRecognizer.
override func viewDidLoad() {
super.viewDidLoad()
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped(_:)))
view.addGestureRecognizer(tapRecognizer)
}
func backgroundTapped(sender: UITapGestureRecognizer) {
view.endEditing(true)
}
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!!!