So I am quite new to coding, learning Swift 3 on Udemy. I'm trying to test my skills by building a music app that contains 3 sound files, at the moment I am struggling to get the image of the current song that should be playing once my UIButton is pressed. I have created an array containing the image files but for some reason it only shows 2 out of the 3 images and will not go further nor will it let me loop the images, any and all suggestions are welcome.
I have tried a for-in loop which is not what I want at the moment. I am trying to get the function to update songImage to accept my array and link to the sender.tag property to cycle through the images
class ViewController: UIViewController {
// Instance Variables
var playTheSong : AVAudioPlayer!
var imageArray = ["songImage1", "songImage2", "songImage3"]
var allSongNamesAndDescriptions = MusicClassBank()
var nextImage = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
albumArtwork.image = UIImage(named: "songImage3")
}
#IBAction func buttonPressed(_ sender: UIButton) {
updateSongImage(selectedImageFile: imageArray[sender.tag - 1])
nextImage = nextImage + 1
}
#IBOutlet weak var albumArtwork: UIImageView!
#IBOutlet weak var nameOfSong: UILabel!
#IBOutlet weak var songDescription: UILabel!
// Cycle through images upon button being pressed.
func updateSongImage(selectedImageFile : String) {
if nextImage <= 3 {
albumArtwork.image = UIImage(named: selectedImageFile)
}
else {
nextImage = 0
}
}
Right now the code is showing just the image displayed upon view load and the next image in the array. I cannot get it to go through the entire array and keep going when the button is pressed.
You are using the "next" UIButton sender.tag as a parameter to change the image, but that tag never changes. So:
In your viewDidLoad() method, you show the third image
When you press the "next" button, you update the image to 1 (probably the sender.tag is 1)
Pressing the button again don't update the image
You can try something like this:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//Set the first image
updateSongImage(selectedImageFile : imageArray[0])
}
#IBAction func buttonPressed(_ sender: UIButton) {
//If nextImage is less than imageArray.count - 1 (because arrays start with 0), add one to nextImage. Else, nextImage return to zero
nextImage = nextImage < imageArray.count - 1 ? nextImage + 1 : 0
updateSongImage(selectedImageFile: imageArray[nextImage])
}
func updateSongImage(selectedImageFile : String) {
//Here we only need to update the image, because the if is outside
albumArtwork.image = UIImage(named: selectedImageFile)
}
Related
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 do I make a back button? I get it wrong the way I want to do it. Thank you in advance.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var imageView: UIImageView!
let images: [UIImage] = [#imageLiteral(resourceName: "tub"),#imageLiteral(resourceName: "ball"),#imageLiteral(resourceName: "apple"),#imageLiteral(resourceName: "igloo"),#imageLiteral(resourceName: "frog")]
var i : Int = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func nextButton(_ sender: UIButton) {
i = (i+1)%images.count
imageView.image = images[i]
}
#IBAction func backButton(_ sender: UIButton) {
i = (i-1)%images.count
imageView.image = images[i]
}
the back button gives an error
You have 5 images in your array.
When you tap your Back button, suppose i is currently equal to 0:
(i-1) == -1
-1 % 5 == -1
imageView.image = images[-1] // is invalid... there is no array index of -1
If you want the Back button to "wrap around" from 0 (the first image) to 4 (the last image), you should do:
i -= 1
if i < 0 {
i = images.count - 1
}
imageView.image = images[i]
If you want to stop at the first image:
i = max(i - 1, 0)
imageView.image = images[i]
I have an array that contains different information,
how can I iterate through the array with a button press? I have two buttons, and I need to allow one to move forward in the array and the back button to display the previous index.
#IBOutlet weak var backButton: UIButton!
#IBOutlet weak var nextButton: UIButton!
#IBOutlet weak var infoLabel: UILabel!
#IBOutlet weak var pageControl: UIPageControl!
Let infoArray = ["info1","info2","info3","info4"]
#IBAction func nextTapped(_ sender: Any) {
// Change the label based on the selected index in array
}
#IBAction func backTapped(_ sender: Any) {
//Return to previous index and update label text
}
I also added page control for better UX, but for now I'm just worried about learning how to even change the label through button Tap.
My guess would be to start the index at 0 which would be info1 and go from there. I can worry about saving index state later.
Any help is much appreciated.
The logic should look something like this
let infoArray = ["info1","info2","info3","info4"]
func viewDidLoad() {
pageControl.numberOfPages = infoArray.count
pageControl.currentPage = 0
}
#IBAction func nextTapped(_ sender: Any) {
// Change the label based on the selected index in array
guard pageControl.currentPage + 1 < infoArray.count else {
return
}
pageControl.currentPage += 1
}
#IBAction func backTapped(_ sender: Any) {
//Return to previous index and update label text
guard pageControl.currentPage - 1 >= 0 else {
return
}
pageControl.currentPage -= 1
}
When a user taps a page control to move to the next or previous page, the control sends the valueChanged event for handling by the delegate. The delegate can then evaluate the currentPage property to determine the page to display. The page control advances only one page in either direction.
Please check the below code you can do something like this to move your array forward and backward. Please add other checks according to your need.
var i = 0
let infoArray = ["info1","info2","info3","info4"]
#IBAction func nextTapped(_ sender: Any) {
// Change the label based on the selected index in array
if i >= 0 && i < infoArray.count{
dataLbl.text = infoArray[i]
}
if i > 3 {
i = i-1
} else {
i = i+1
}
}
#IBAction func backTapped(_ sender: Any) {
//Return to previous index and update label text
if i >= 0 && i < infoArray.count-1 {
dataLbl.text = infoArray[i]
}
if i < 0 {
i = i+1
} else {
i = i-1
}
}
there was a question like this already made but I tried the suggestions and it didn't work for me still. :/
I am trying to make a quiz app using this tutorial: https://www.youtube.com/watch?v=KNAQ3Y8PGkM&t=1s
Here is a link to download my project: https://www.dropbox.com/s/bwvg6fyrrzudued/kat%20quiz.zip?dl=0
Everything is perfect except I get the error:
Could not cast value of type 'UIView' (0x10d54a4c0) to 'UIButton' (0x10d552120)
I'd really appreciate some help. I tried everything in my knowledge and searching, thank you. :)
import UIKit
class ViewController: UIViewController {
let questions = ["What color is Courage the Cowardly Dog?", "What is the name of the woman that lives with Courage?", "What is the name of the man that lives with Courage?"]
let answers = [["Purple","Grey","Orange"],["Muriel", "Angela", "Elizabeth"], ["Eustace", "Robert", "Ezio"]]
//Variables
var currentQuestion = 0
var rightAnswerPlacement:UInt32 = 0
var points = 0
//Label
#IBOutlet weak var lbl: UILabel!
//Button
#IBAction func action(_ sender: AnyObject) {
if (sender.tag == Int(rightAnswerPlacement))
{
print ("RIGHT!")
points += 1
}
else
{
print ("WRONG!!!!!!")
}
if (currentQuestion != questions.count)
{
newQuestion()
}
else{
performSegue(withIdentifier: "showScore", sender: self)
}
}
override func viewDidAppear(_ animated: Bool) {
newQuestion()
}
//Function that displays new question
func newQuestion(){
lbl.text = questions[currentQuestion]
rightAnswerPlacement = arc4random_uniform(3)+1
//Create a button
var button:UIButton = UIButton()
var x = 1
for i in 1...3
{
//Create a button
button = view.viewWithTag(i) as! UIButton
if (i == Int(rightAnswerPlacement))
{
button.setTitle(answers[currentQuestion][0], for: .normal)
}
else
{
button.setTitle(answers[currentQuestion][x], for: .normal)
x = 2
}
}
currentQuestion += 1
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Did you create UI Button in your Story Board ??
In your youtube video, watch 1:45
And remember to set your 3 UI Button's tag to 1, 2 and 3
watch 3:20
Your problem occurs because you've set your View's tag = 1.
You can fix it easily by change View's tag value to a number != 1, 2 and 3
Because your ViewController have 2 view with the same tag = 1. (view and UI Button).
So when you use view.viewWithTag(i), It accidentally select view not UI Button. So it can not convert to UI Button type
P/s: next time, if you want to select your Button directly, you can make an #IBOutlet for that Button as you make with your Label. It will not cause confusing error like that
I'm building a simple tic tac toe game and I would like to same each "X" or "O" in an array so that when the user leaves the screen and comes back the game reloads.
I can get it to print to the output screen but it doesn't show up in the IOS simulator. I've only have the first two squares coded because I was hoping to get the array to work before I moved on to the rest.
Here's my code:
import UIKit
var gamePieces3 = NSMutableArray()
class GameViewController3 : UIViewController {
#IBOutlet var button0 : UIButton !
#IBOutlet var button1 : UIButton !
#IBOutlet var spot0 : UIImageView !
#IBOutlet var spot1 : UIImageView !
#IBAction func addGamePiece0(button0 : AnyObject) {
if (goNumber % 2 == 0) {
let image2 = UIImage(named : "cross.png")
spot0.image = image2
}
else {
let image1 = UIImage(named : "circle.png")
spot0.image = image1
}
gamePieces3.addObject(spot0)
goNumber++
}
#IBAction func addGamePiece1(button1 : AnyObject) {
if (goNumber % 2 == 0) {
let image2 = UIImage(named : "cross.png")
spot1.image = image2
}
else {
let image1 = UIImage(named : "circle.png")
spot1.image = image1
}
gamePieces3.addObject(spot1)
goNumber++
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func viewDidAppear(animated : Bool) {
print(gamePieces3)
}
}
There are more things you need to implement in your code if you want your app to "remember" where it left off from last app close or exit. Since you only want to store which button location stores "cross" or "circle", I think most suitable and easy way to do is using NSUserDefaults. It works very similar to a Dictionary. You can put something like "Button0" all the way to "Button8" as keys, and "cross.png" or "circle.png" as value. Every time your gamePieces3 is changed, you need to change that NSUserDefaults accordingly. Then in you videDidLoad, you want to read from your NSUserDefaults. Scan through NSUserDefaults, and apply "cross.png" or "circle.png" accordingly to controller's view.
self.view.addSubview(<ImageView with your image>);