When I taped button UILabel appears and immediately disappears again. I need it to disappear after a few seconds. It's my first app and I can't solve this problem.
Thanks!
func done() {
if sauserImageView.isHidden == false && cupImageView.isHidden == false && spoonImageView.isHidden == false {
winningLabel.isHidden = false
}
}
You can perform a delayed action by using the DispatchQueue API, e.g.
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.label.isHidden = true
}
Or if you want to animate the hiding, use UIView.animate(withDuration:animations:) or UIView.animate(withDuration:delay:options:animations:completion:) e.g.:
UIView.animate(withDuration: 2) {
self.label.alpha = 0
}
Good luck!
Related
In a simple memory game I have a struct that defines the two cards that are tapped and returns in mutating functions the integers firstFlippedCard and secondFlippedCard.
If these do not match by another property, I want both cards to 'flip back'. I made a transition function for this - however, I can only make the last tapped button to switch back using the following logic:
#IBAction func cardsPress(_ sender: UIButton) {
flip(sender: sender)
if cardBrain.checkFirstCard(card: sender.tag - 1) == true {
//stay flipped
} else if cardBrain.checkForMatch(card: sender.tag - 1).match == true {
//stay flipped
} else {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
self.backFlip(sender: sender)
})
}
}
Note that multiple UIButtons are linked to cardsPress. How can I make them both flip back instead of only the sender?
Add a property to keep track of the previousButton pressed. Then use this property to flip both the current sender and the previousButton. Finally, set previousButton back to nil after flipping it or deciding to keep it flipped.
var previousButton: UIButton?
var waitForFlip = false
#IBAction func cardsPress(_ sender: UIButton) {
// ignore button input while waiting for cards to unflip
guard !waitForFlip else { return }
flip(sender: sender)
if cardBrain.checkFirstCard(card: sender.tag - 1) {
//stay flipped
previousButton = sender
} else if cardBrain.checkForMatch(card: sender.tag - 1).match {
//stay flipped
previousButton = nil
} else {
waitForFlip = true
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
self.backFlip(sender: sender)
if let button = previousButton {
self.backFlip(sender: button)
self.previousButton = nil
}
self.waitForFlip = false
})
}
}
Notes:
There is a possibility that the player could start flipping another card before the previous ones flip back. I introduced a waitForFlip property to ignore button inputs while we are waiting for the mismatched cards to flip back to avoid an issue where previousButton gets set and then overwritten to nil by the previous unflip.
There is no need to check if a Bool value is == true. Simply check if boolValue { instead of if boolValue == true. I removed two instances of that.
You might want to disable the buttons of cards that have been flipped (set sender.isEnabled = false) to keep the player from selecting a flipped card. Remember to reenable them again when they are flipped back by setting their isEnabled properties to true.
I am currently learning Swift and can not continue. I create a dice game. If the "if query" is true, the program should pause briefly before a new query is possible.
#IBAction func guess(_ sender: Any) {
let diceRoll = arc4random_uniform(5)
let fingerErgebnis = diceRoll + 1
let fingerAntwort = String(fingerErgebnis)
if fingerTextfield.text == fingerAntwort{
ergebnis.text = "Richtig erraten!"
ergebnis.textColor = UIColor.green
ergebnis.font = ergebnis.font.withSize(20)
bild.image = UIImage(named: ("win.jpg"))
button.setTitle("Neues Spiel!", for: .normal)
fingerTextfield.text = " "
sleep (2)
}else if fingerErgebnis == 1 {
ergebnis.text = "Leider falsch! Die Zahl war \(fingerAntwort)."
ergebnis.textColor = UIColor.red
bild.image = UIImage(named: ("finger1.jpg"))
button.setTitle("Versuch es nochmal!", for: .normal)
} ...
As far as everything works, but I want that everything is running first and I have to wait 2 seconds until I can click the button again. My test is paused first, then the rest of the if commands are executed. I want that the other way around.
Sorry for my terrible english ;)
You can disable your button and re-enable it after two seconds using async(deadline:execute:). So, instead of sleep(2) put the following:
button.isUserInteractionEnabled = false
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [weak self] in
// assuming button is a property of the current view controller
self?.button.isUserInteractionEnabled = true
}
sleep (2)
This is the wrong way to create the delay you're looking for. sleep() stops your process entirely, at least on that thread. What you should do instead is to disable the button and then use a Timer (or some other form of delayed execution, but Timer is easy) to re-enable it two seconds later.
I need to scroll the table to bottom.When i write the code of scrolling the table in viewwilAppear it does not work,but when i write the same code in viewDidAppear it works but user see the scrolling. I do not want to see the user , scrolling how to make tableScrolling in ViewWillAppear.`
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
UIApplication.sharedApplication().delegate!.window!!.windowLevel = UIWindowLevelNormal
self.view.backgroundColor = UIColor.whiteColor()
viewWillAppearExecuted = true
executeCodeOfViewViewAppear()
}
func executeCodeOfViewViewAppear() {
if viewWillAppearExecuted {
viewWillAppearExecuted = false
if appNeedsAutoResize{
self.noLongerParticipantMessageLabel.font = UIUtils.getFontForApproprieteField(.Footnote).font
self.typingStatusLabel.font = UIUtils.getFontForApproprieteField(.Headline).font
}
withAnimationFlag = true
if !self.composeBar.textView.isFirstResponder()
{
// This block will execute if compose bar is first responder
self.updateTableBottomCnt(value:self.composeBar.frame.size.height)
// Update compose bar constarint
if self.composeBarBottomConstraing.constant != 0
{
self.composeBarBottomConstraing.constant = 0
}
}
self.isOpenNextScreen = false
self.checkIfloginUserisActiveMember()
self.tabBarController?.tabBar.hidden = true
ChatCommonCall.sharedInstance.currentThreadIdForPush = self.threadInfo.threadId
// This block is used for make a responder to keyboard for send message.
if shouldComposeBarFirstResponder == true {
self.composeBar.becomeFirstResponder()
shouldComposeBarFirstResponder = false
}
self.showMessageById(self.messageIdForMessageDisplay)
ChatCommonCall.sharedInstance.isChatModuleScreen = true
self.changeFrame()
self.composeBar.button.enabled = self.composeBar.text.trim().length > 0 ? true : false
/// Table frame changes.
switch self.optType
{
case .NewMessageSection:
break
case .DoNotHandle :
break
case .None :
if !(self.messageIdForMessageDisplay.isEqual(Guid.emptyGuid()))
{
self.optType = .ShowMessageOfID(id: self.messageIdForMessageDisplay)
}
else {
self.optType = .ScrollToBottom
}
break
default :
break
}
switch self.optType
{
case .NewMessageSection :
break
default :
self.handleOptType()
}
//Implemented the new observer pattern in the whole project where we suppose to refresh the screen for background sync data
//By Nikhil Kumar Saraf on 19 July 2016
Notifier.Unregister()
let observer = DatabaseObserverInfo(tName: ["chatthread","chatthreadmember","chatmessage","chatmessagereceiver","chatthumbnail","pfthumbnail","chatmessagemarker"], oType: [SyncOpType.Insert,SyncOpType.Update,SyncOpType.Delete], observer: self, stick: false, syncTrigger: SyncTriggerType.Post)
Notifier.Register(observer)
//By Balkrishan Yadav for AutoResizing UI on 30 Nov. 2016
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ChatMessageController.didChangePreferredContentSize(_:)), name:UIContentSizeCategoryDidChangeNotification, object: nil)
// This condition will execute if some one sharing image and coming to the chat message screen
//#Balkrishan Yadav
if ChatCommonCall.sharedInstance.attachmentInfo != nil {
self.addFileInComposeBar(ChatCommonCall.sharedInstance.attachmentInfo!)
ChatCommonCall.sharedInstance.attachmentInfo = nil
let dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.3 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
// your function here
// self.changeController(true)
})
}
}
}
func handleOptType(callFromViewDidAppear:Bool = false) {
switch optType {
case .ScrollToBottom : // No new message is available. show last message. self.messageTableView.setContentOffset(CGPointMake(0,CGFloat.max), animated: !isCameFromThreadComposer)
break
default:
// do nothing
}
If you don't want the scrolling to be animated you just have to pass false as the animated argument to the scrolling function. For example :
tableView.scrollToRow(at: indexPath, at: .top, animated: false)
This function would scroll the indexPath's row to the top of the table view without any animation.
I’m working with Xcode 8 and Swift 3, trying to display a “Resume Game” button on my scene after pausing the game but since everything stops, I have not found a way to properly do so. I followed Mike's advice on this page “Tap To Resume” Pause text SpriteKit, but that didn't help.
When my pause button is tapped, it runs the pause function with the following code:
func pauseGame() {
self.isPaused = true
self.physicsWorld.speed = 0
self.speed = 0.0
self.scene?.view?.isPaused = true
}
It may seem a little overkill but that works. If I remove
self.scene?.view?.isPaused = true
from my pause function, I'm able to display the tap to Resume Button but I can still interact with some of the SpriteKit nodes in the scene. I'm working on a space shooter game so the user can still move the spceship and tap to fire although the bullets don't travel until I resume the scene.
I thought about adding a boolean "true" to the pause function and adding an IF statement to the firing and the moving above but that seems to me like complicating things a bit.
Any suggestions on how I can display the Resume button when pausing the scene?
You can't interact with any nodes on your scene because you've paused it entirely, which pauses all its children, which is everything on the scene. To avoid this, pause only certain SKNodes (layers).
Add certain nodes to different SKNodes so instead of pausing the entire scene, you can only pause the the layer (SKNode) that you wish to pause (gameLayer). It would look something like this:
Initialize the nodes
let gameLayer = SKNode()
let pauseLayer = SKNode()
Now when you want to add a child to the scene, instead add it to the layer that you want it to be a part of:
Add child nodes to the main layers
gameLayer.addChild(gameSceneNode)
pauseLayer.addChild(resumeButton)
Don't forget to add the layers to the scene too
Add the layers to the scene
addChild(gameLayer)
addChild(pauseLayer)
To pause a layer write this:
gameLayer.isPaused = true
Note that in this example, all the nodes on the gameLayer will be paused, however everything on the pauseLayer will not.
Your complete example might look something like this:
func pauseGame() {
gameLayer.isPaused = true
pauseLayer.isHidden = false
gameLayer.physicsWorld.speed = 0
gameLayer.speed = 0.0
}
func unpauseGame() {
gameLayer.isPaused = false
pauseLayer.isHidden = true
// Whatever else you need to undo
}
For my next game I'm sure I'll give Nik's suggestion a try. As for my issue above, it worked by using the code shown below. The additional code is to dismiss the pause button as well. Now that this works I can maybe add a fadeIn and fadeOut actions to both buttons.
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let pointOfTouch = touch.location(in: self)
let nodeUserTapped = atPoint(pointOfTouch)
if nodeUserTapped.name == "PauseButton" {
if (self.isPaused == false) {
pauseGame()
}
}
if nodeUserTapped.name == "ResumeButton" {
if (self.isPaused == true) {
resumeGame()
}
}
}
}
// MARK: - pauseGame
func pauseGame() {
self.isPaused = true
currentGameState = gameState.pauseGame
self.physicsWorld.speed = 0
self.speed = 0.0
if (backgroundMusicIsOn == true) {
backingAudio.stop()
}
if resumeButton.isHidden == true {
resumeButton.isHidden = false
}
if pauseButton.isHidden == false {
pauseButton.isHidden = true
}
}
// MARK: - resumeGame
func resumeGame() {
self.isPaused = false
currentGameState = gameState.inGame
self.physicsWorld.speed = 1
self.speed = 1.0
if (backgroundMusicIsOn == true) {
backingAudio.play()
}
if resumeButton.isHidden == false {
resumeButton.isHidden = true
}
if pauseButton.isHidden == true {
pauseButton.isHidden = false
}
}
I'm coding a carousel that display a string array. The string element that is selected is to be displayed in a UIView.
var plotValue:Int = 0
var flag:Int = 1
let plotList: [String] = ["Phenotype","SNP","Synthesis","PheWAS","Circos"]
Basically, the user can swipe left or right the UILabel gets updated with a new value from the plotList.
Swipe left decrements a counter by -1, swipe right increments a counter by +1.
If the user reaches the initial value of the plotList[0] continues swiping left, the code will wrap around and start from the maximum element in the plotList.
If the user reaches the maximum value of the plotList and continues to swipe right, the code will wrap around and start from the plotList[0].
Once the users taps the UIView, another process is launched.
var swipeCarouselLeft: UISwipeGestureRecognizer =
UISwipeGestureRecognizer(target: self, action: "carouselLeft")
swipeCarouselLeft.direction = UISwipeGestureRecognizerDirection.Left
self.labelView.addGestureRecognizer(swipeCarouselLeft)
var swipeCarouselRight: UISwipeGestureRecognizer =
UISwipeGestureRecognizer(target: self, action: "carouselRight")
swipeCarouselRight.direction = UISwipeGestureRecognizerDirection.Right
self.labelView.addGestureRecognizer(swipeCarouselRight)
var tapButton:UITapGestureRecognizer =
UITapGestureRecognizer(target: self, action: "carouselTap")
self.labelView.addGestureRecognizer(tapButton)
Here are the functions defined.
func carouselLeft(){
AudioServicesPlaySystemSound(1052)
flag = -1
getLabel(flag)
}
func carouselRight(){
AudioServicesPlaySystemSound(1054)
flag = 1
getLabel(flag)
}
and
func getLabel(flag: Int){
plotValue = plotValue + flag
println("plotValue \(plotValue)")
switch plotValue {
case (plotList.count):
plotValue = 0
case (-1):
plotValue = plotList.count - 1
default:
plotValue = 0
}
UIView.animateWithDuration(2, animations: { () -> Void in
self.labelOutlet.textColor = UIColor.blueColor()
})
self.labelOutlet.text = plotList[plotValue]
println("\(plotList[plotValue])UIView")
}
func carouselTap(){
AudioServicesPlaySystemSound(1057)
}
Basically, when user swipe the resulting string is either the first or last element in the plotList array, none of the other elements in the array are shown.
Maybe I'm overthinking this and there's a simpler way to do this? or the Apple "preferred" way of doing this? or a more OOP??
Changed the logic to this and works and will wrap in both directions.
func getLabel(flag: Int){
if (flag == -1 && plotValue == 0){
plotValue = plotList.count - 1
}
else if (flag == 1 && plotValue == plotList.count - 1)
{
plotValue = 0
}
else
{
plotValue = plotValue + flag
}
UIView.animateWithDuration(2, animations: { () -> Void in
self.labelOutlet.textColor = UIColor.blueColor()
})
self.labelOutlet.text = plotList[plotValue]
}