Swift animation not sticking [duplicate] - ios

This question already has an answer here:
UIView layout being reset
(1 answer)
Closed 8 years ago.
I have a button when clicked I move an imageView with animation to another location on the screen with the following code:
#IBOutlet var CurrentPlayerTotal: UILabel!
#IBOutlet var Player1: UIImageView!
UIImageView.animateWithDuration(1.0, animations: {
self.Player1.frame = CGRect(x: 16, y: 178, width: 250, height: 350)
})
The image moves fine.
I have another button that updates a label on the screen.
#IBAction func Sub1(sender: AnyObject) {
currentTotal -= 1
CurrentPlayerTotal.text = "\(currentTotal )"
}
When I click this button the image returns to the original location. Why is this happening?
Here is a more complete code snippet
var currentTotal : Int = 0
var currentPlayer : Int = 1
var numberOfPlayers : Int = 6
#IBOutlet var CurrentPlayerTotal: UILabel!
#IBOutlet var CurrentPlayerNme: UILabel!
#IBOutlet var Player1: UIImageView!
override func viewDidAppear(animated: Bool) {
UIImageView.animateWithDuration(1, delay: 1.0, options: .CurveEaseOut, animations: {
var player = self.Player1.frame
player = CGRect(x: 16, y: 178, width: 250, height: 350)
self.Player1.frame = player
}, completion: { finished in
println("done")
})
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
// SUBTRACT
#IBAction func Sub1(sender: AnyObject) {
currentTotal -= 1
CurrentPlayerTotal.text = "\(currentTotal )"
}
The app begins the image moves to the correct spot. When I click on the button bound to the Sub1 func the image pops back to the original spot.

Try first option if it works then okay, otherwise try the second one, it will work definitely.
self.player1.layoutIfNeeded()
self.player1 setNeedsDisplay()
Make outlet of the NSLayoutConstraint for uiimageview and plus/minus it as per your need rather chaging frame of the uimageview.

Related

Switching between two strings after button is pressed

So I am working on a BlackJack game for iOS using Swift. I have two buttons, HIT and STAY. Here is where my problem lies: When I press the originally, it is player 1's turn. But after clicking the HIT button, I want the turn label to oscillate between player 2 and player 1. So after player 1 clicks HIT button, I want the turn label to read player 2 and then player 1. Here is what I got so far:
class ViewController: UIViewController {
var deck = PlayingCardDeck()
#IBOutlet weak var cardLabel: UILabel!
#IBOutlet weak var playerTurn: UILabel!
#IBOutlet weak var scorePlayerOne: UILabel!
#IBOutlet weak var scorePlayerTwo: UILabel!
#IBAction func btnHit(_ sender: Any) {
cardLabel.text = String(describing: deck.drawCard()!)
playerTurn.text = String(describing: "Player 2")
}
#IBAction func btnStay(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
deck.shuffle()
}
}
With the method I have, it mimics what I want to happen (switches to player 2)
You need a variable to track which player is currently playing and then change the label based on those variable value.
var isFirstPlayerTurn: Bool = true
#IBAction func btnHit(_ sender: Any) {
cardLabel.text = String(describing: deck.drawCard()!)
isFirstPlayerTurn = !isFirstPlayerTurn
playerTurn.text = isFirstPlayerTurn ? "Player 1" : "Player 2"
}
Create two labels, one for each player. Then hide player 2's label and flip it while hidden in viewDidLoad(). Once the turn changes, flip both labels while simultaneously showing and hiding the labels based who's turn it is.
To flip the label, use CGAffineTransform. Use the labels' alpha property to show and hide the labels.
func changeTurn(_ player: Int) {
UIView.animate(withDuration: 0.5) {
playerTurn1.transform = CGAffineTransform(scaleX: -playerTurn1.transform.a, y: playerTurn1.transform.d)
playerTurn2.transform = CGAffineTransform(scaleX: -playerTurn2.transform.a, y: playerTurn2.transform.d)
playerTurn1.alpha = player == 1 ? 1 : 0
playerTurn2.alpha = player == 2 ? 1 : 0
}
}
Usage:
#IBOutlet weak var playerTurn1: UILabel!
#IBOutlet weak var playerTurn2: UILabel!
private var turn = 1
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
deck.shuffle()
playerTurn2.alpha = 0
playerTurn2.transform = CGAffineTransform(scaleX: -playerTurn2.transform.a, y: playerTurn2.transform.d)
}
#IBAction func btnHit(_ sender: Any) {
cardLabel.text = String(describing: deck.drawCard()!)
turn = turn == 1 ? 2 : 1
changeTurn(turn)
}
Make sure both labels are the same frames.

How can I create a button that makes new Object as previous one in Swift?

I want to create a button that makes a new image. But this new image should be the same as the first one (bild).
I also tried to see what is working with print command.
The console shows all the prints but nothing more happens when I click the button. The new image is not appearing in the app.
I don't have any more ideas about that problem.
#IBOutlet weak var bild: UIImageView!
#IBAction func NewImage_btn(_ sender: Any) {
let newImage = UIImageView(frame: bild.frame)
print("0")
let newY = bild.frame.origin.y + 40.0
print("1")
newImage.frame.origin.y = newY
print("2")
self.view.addSubview(newImage)
print("3")
}
At first you need to set an image to it for see it, second you don't need to add it to view again: so here is working:
#IBOutlet weak var bild: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func NewImage_btn(_ sender: Any) {
let newImage = UIImageView(frame: CGRect(x: bild.frame.origin.x, y: bild.frame.origin.y + 40, width: bild.frame.width, height: bild.frame.height))
newImage.image = UIImage(named:"Your image name")
}
I think the missing line is
newImage.image = bild.image

Use animations to show color sequence (Swift)

Hi I'm new to Swift and I want to create a color memory game for IPhone where your app gives you a sequence of colors and you have to repeat it by pressing the right buttons. The sequence becomes longer and longer everytime you pressed the right buttons of the previous sequence.
I want the app to show which button is pressed by using an animation on the button. The sequence will make the buttons flash and then the user can recreate the sequence.
I have a method that does the flash(), which is a part of a class which is an extension of UIButton
func flash() {
let flash = CABasicAnimation(keyPath: "opacity")
flash.duration = 0.2
flash.fromValue = 1
flash.toValue = 0.1
flash.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
flash.autoreverses = true
flash.repeatCount = 1
layer.add(flash, forKey: nil)
}
When I perform this method on a sequence of buttons it flashes all of the buttons, written in the sequence, at the same time. This is not the way I want it of course, I want the buttons to flash one after another.
// ViewController.swift
import UIKit
import SpriteKit
class GameViewController: UIViewController {
var colorPattern = [Int]()
#IBOutlet weak var buttonGreen: UIButton!
#IBOutlet weak var buttonRed: UIButton!
#IBOutlet weak var buttonBlue: UIButton!
#IBOutlet weak var buttonYellow: UIButton!
var buttons = [UIButton]()
override func viewDidLoad() {
super.viewDidLoad()
buttons = [buttonGreen, buttonRed, buttonBlue, buttonYellow]
colorPattern = [0, 1, 2, 0, 1, 2]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func colorButtonTouched(_ sender: UIButton) {
print("button touched: ", sender.titleLabel!.text!)
//sender.flash()
doPattern()
}
func doPattern() {
UIView.animateKeyframes(withDuration: 1, delay: 0, options: [.calculationModeCubic], animations: {
// Add animations
for index in self.colorPattern{
print(index);
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1, animations: self.buttons[index].flash)
}
}, completion:{ _ in
print("I'm done!")
})
}
}
When I perform this code button 1, 2 and 3 flash at the same time. Is there a way to fix this? or are animations just not the right way to go with looping sequences.
Try this
var currentButtonIndex = 0
func doPattern()
{
let currentButton = self.buttons[self.currentButtonIndex]
UIView.animateKeyframes(withDuration: 1, delay: 0, options: [.autoreverse], animations: {
currentButton.alpha = 0
}) { (complete) in
currentButton.alpha = 1
if self.currentButtonIndex == self.buttons.count - 1
{
self.currentButtonIndex = 0
return
}
self.currentButtonIndex += 1
self.doPattern()
}
}

Swift viewDidLoad() in second View Controller Scene not working

I'm a beginner at swift and Xcode, so this question may sound very simple.
I have two view controllers, connected by a segue. My first view controller scene runs code from the viewDidLoad() function, and then calls the .performSegue() function for the second view controller scene to get displayed.
But now, I want to run code in that new .swift file. viewDidLoad() doesn't seem to work, so how do I get around this problem? Where else could I put my code, or what function should it be in?
EDIT
// Show main menu
self.performSegue(withIdentifier: "MenuSegue", sender: self)
is how I am switching between view controllers. The buttons display, but anything I write in viewDidLoad() does not work
EDIT 2
My code for ViewController.swift:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var startScreen: UIStackView! // H2O start screen
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Display start screen for 2 seconds before fading out
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2, execute: {
// Fade out start screen
UIView.animate(withDuration: 1, animations: {self.startScreen.alpha = 0})
// Wait 1 second from when start screen starts to fade out
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1, execute: {
// Show main menu
self.performSegue(withIdentifier: "MenuSegue", sender: self)
})
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
And for MenuViewController.swift:
import UIKit
class MenuViewController: UIViewController {
#IBOutlet weak var playButton: UIButton! // Play button
#IBOutlet weak var settingsButton: UIButton! // Settings button
#IBOutlet weak var volumeButton: UIButton! // Volume button
#IBOutlet weak var volumeStack: UIStackView! // Volume stack
#IBOutlet weak var volumePercentage: UILabel! // Volume percentage
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
print("Hello")
// Slowly display everything
playButton.alpha = 0
settingsButton.alpha = 0
volumeButton.alpha = 0
volumeStack.alpha = 0
// Fade out start screen
UIView.animate(withDuration: 1, animations: {self.playButton.alpha = 1; self.settingsButton.alpha = 1; self.volumeButton.alpha = 1; self.volumeStack.alpha = 1})
print("Hi")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func settings(_ sender: UIButton) {
// If the settings are hidden
if volumeButton.alpha == 0 {
// Rotate settings button to open settings
UIView.animate(withDuration: 0.5, animations: {sender.transform = CGAffineTransform(rotationAngle: .pi * -0.999)})
// Show extended settings
UIView.animate(withDuration: 0.5, animations: {self.volumeButton.alpha = 1})
}
else {
// Rotate settings button back to normal
UIView.animate(withDuration: 0.5, animations: {sender.transform = CGAffineTransform(rotationAngle: 0.0)})
// Hide extended settings
UIView.animate(withDuration: 0.5, animations: {self.volumeButton.alpha = 0})
}
}
#IBAction func volumeSlider(_ sender: UISlider) {
// Get slider value rounded to nearest 5
let value = round(sender.value / 5) * 5
// Set the value to nearest 5
sender.value = value
// Show volume percentage
volumePercentage.text = "\(Int(value))%"
}
#IBAction func playButton(_ sender: UIButton) {
// Hide all settings
settingsButton.alpha = 0
volumeButton.alpha = 0
volumeStack.alpha = 0
// Hide play button
sender.alpha = 0
}
}
Add your animation code inside viewWillAppear() method.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Add animation code here
}

Swift - label updates with SwiftRangeSlider

I am trying to work with SwiftRangeSlider implemented by BrianCorbin:
https://github.com/BrianCorbin/SwiftRangeSlider
#IBOutlet weak var labelForRangeSlider: UILabel!
#IBOutlet weak var rangeSlider: RangeSlider!
#IBOutlet weak var submitButton: UIButton!
override func viewDidLayoutSubviews() {
rangeSlider.updateLayerFrames()
}
...
And this shows:
I want to update "Time", which is labelForRangeSlider, as rangeSlider's lowerValue and upperValue change.
You are supposed to add action for the event .valueChanged for SwiftRangeSlider:
override func viewDidLoad() {
super.viewDidLoad()
let rangeSlider: RangeSlider = RangeSlider(frame: CGRect(x: 0, y: 0, width: 200, height: 60))
rangeSlider.addTarget(self, action: #selector(self.rangeSliderValueChanged(slider:)), for: UIControlEvents.valueChanged)
self.view.addSubview(rangeSlider)
}
#IBAction func rangeSliderValueChanged(slider: RangeSlider) {
print(slider.lowerValue)
}
Connect the IBAction below to the range slider in your storyboard and than you can change your label when you move the slider. You need to check lowerValue and upperValue of your slider.
#IBAction func rangeSliderValuesChanged(_ rangeSlider: slider) {
labelForRangeSlider.text "Min: \(slider.lowerValue), Max: (slider.upperValue)")
}

Resources