On a viewcontroller I have 101 buttons. If one of the first 100 buttons is pressed, I want to change the image of button number 101 ( I have 100 images in this project; image1,image2,image3 etc.)
So I have done this by giving every button a tag from 0-100 and then make a switch statement based on sender.tag
#IBOutlet weak var button101 : UIButton!
var i = 1
// I hooked up all the other 100 buttons to a single IBAction
#IBAction func buttonTapped(sender: UIButton) {
switch sender.tag {
case 0: i = 1
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case 1: i = 2
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case 2: i = 3
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case ..: // etc. until case 99 (because button 100 has tag 99)
default: break
This super ugly code works: It changes the image of button number 101 into the specified image(i). But I want a more elegant and better solution.
I have 2 questions:
How to initialise the 'image' constant/variable in a better way (outside the IBAction)?
What kind of (loop)statement to use instead of this large switch statement?
So: I want to determine which button is pressed, then update the value of var i, loop through the images and find and update the image of button101 with the image(i).
I hope my questions are clear. Please let me know if they are not.
Help is much appreciated!
Your switch statement acts the same as:
if sender.tag < 100 {
let image = UIImage (named: "image\(sender.tag + 1)")
button101.setImage(image, forState:.Normal)
}
You can put your UIImage at the top of your ViewController with var UIImage: UIImage! if you want to, but I do not see any reason to do this.
Related
Hi I am new to coding with Swift and I am also pretty new to Stackoverflow. How do I make a button that changes the image for about 5 seconds and then go back to the original image when the user taps on the button?
I've tried using this code
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), {
gauntletImage.image = UIImage(named: gauntlet["gauntlet2"]) //change back to the old image after 5 sec
});
But I keep getting these 2 errors:
Cannot convert value of type 'Int' to expected argument type 'dispatch_time_t' (aka 'UInt64')
and
Ambiguous use of 'dispatch_get_main_queue()'
This is more of my code that I am using.
#IBOutlet weak var gauntletImage: UIImageView!
let gauntlet = ["gauntlet1", "gauntlet2", "gauntlet3", "gauntlet4", "gauntlet5", "gauntlet6",]
#IBAction func stonePressed(_ sender: UIButton) {
print(sender.tag)
gauntletImage.image = UIImage(named: gauntlet[sender.tag - 1]) //change to the new image
dispatch_after(dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), (Int64)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), {
gauntletImage.image = UIImage(named: gauntlet["gauntlet2"]) //change back to the old image after 5 sec
});
}
You can try
#IBAction func stonePressed(_ sender: UIButton) {
// store old image assuming it has an initial image in storyboard
let oldImg = gauntletImage.image!
// set new image
gauntletImage.image = UIImage(named: gauntlet[sender.tag - 1])
// wait 5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 5 ) {
// set back old image
self.gauntletImage.image = oldImg
}
}
User may click it multiple times so you may do
sender.isEnabled = false
when storing the old image and setting it back to true inside the dispatch after block
Using code found in another post on here, I was able to programmatically draw and erase a subview, including location, width, and height, as shown in func addLoadButton and func removeSubview below. I have also figured out how to programmatically draw a picture on the main View Controller, as shown in func trailerLoadImage below. However, after many hours and attempts, I have tried to programmatically add and remove images into that subview without success.
My end goal is to be able to press three different trailer load type buttons to insert three different images (button 1 loads image 1, button 2 loads image 2, etc.) in a subview located in a specific location on the screen, and to be able to remove the images one at a time (may not be in order put on screen) by tapping on the images with a finger. The subview can be permanent or can be created and removed programmatically (as used below).
What code would I use to insert an image or multiple different images into a subview that has already been created, to remove the image(s) in the reverse order added, and to clear all images out of the subview? If this can’t be done, an acceptable alternative would be the ability to remove the image from the main VC by either tapping on it or pressing a button to clear all added images.
//Class declaration
class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate {
//Boolean to include load type one in calculations
var trailerLoad : Bool = false
var trailerLoadDistanceFromFront = 20
//Boolean to include load type two in calculations
var trailerLoadTwo : Bool = false
var trailerLoadTwoDistanceFromFront = 80
//Boolean to include load type three in calculations
var trailerLoadThree : Bool = false
var trailerLoadThreeDistanceFromFront = 120
var trailerLoadWidth : Int = 0
var trailerLoadX : Int = 0
//Boolean true only when subView on trailer is active
var subViewActive : Bool = false
override func viewDidLoad() {
super.viewDidLoad()
//Picker view data sources and delegates included in here and work fine
}
//Adds subview for loads
#IBAction func addLoadButton(_ sender: Any) {
let trailerLoadView: UIView = UIView(frame: CGRect(x: 252, y: 233, width: 378, height: 100))
trailerLoadView.backgroundColor = .blue
trailerLoadView.alpha = 0.5
trailerLoadView.tag = 100
trailerLoadView.isUserInteractionEnabled = true
self.view.addSubview(trailerLoadView)
subViewActive = true
}
//If subViewActive is true, calls alert to get distance load type one is from front, moves on to insert and position image, changes trailerLoad bool to true
#IBAction func trailerLoadOneButton(_ sender: Any) {
//If subViewActive is true:
//Calls alert to get distance load type one is from front, puts in var trailerLoadDistanceFromFront
//Calls trailerLoadImage() to insert and position load type one image
//Changes bool trailerLoad to true
//If subViewActive is false:
//Calls alert to tell user that they need to click Add Load button (create subview) before adding load types one, two, or three
}
//Add trailer load type one image, scales and positions it relatively accurately in view.
//To be duplicated and modified for load types two and three in the future, with different images (trailerLoadTypeTwoPic and trailerLoadTypeThreePic)
func trailerLoadImage() {
trailerLoadWidth = 378 * 60 / trailerTotalLength
trailerLoadX = 378 * trailerLoadDistanceFromFront / trailerTotalLength
let imageView = UIImageView(frame: CGRect(x: (252 + trailerLoadX), y: (333 - trailerLoadWidth), width: trailerLoadWidth, height: trailerLoadWidth));
let image = UIImage(named: “trailerLoadTypeOnePic”);
imageView.image = image;
self.view.addSubview(imageView)
}
//Calls func removeSubview to remove subview
#IBAction func resetButton(_ sender: Any) {
removeSubview()
}
//Removes subview for loads
#objc func removeSubview(){
subViewActive = false
if let viewWithTag = self.view.viewWithTag(100) {
viewWithTag.removeFromSuperview()
}else{
print("No!")
}
}
}
Thank you very much to anybody that offers assistance or advice.
Don't use tags! Just create variables in global scope for your views
var imageViews = [UIImageView]()
then when you need to add them first append them to your array and then add them to view
imageViews.append(imageView)
view.addSubview(imageView)
Then when you need to remove your all views from their superview, use method removeFromSuperview() for each view in array
imageViews.forEach { $0.removeFromSuperview() }
imageViews.removeAll()
or if you need to remove just one view at specific index
imageViews[index].removeFromSuperview()
imageViews.remove(at: index)
I need to make my image jump and move down with animation. I am using sprites to show the jump animation. But, when I try to combine it with move down animation, it does not work. I am trying it on click of a button. Below is my code.
My animation works properly for second click but for first click it just jumps at its current location and at second click it jumps and moves down. I am trying to make it jump and move down at first button click.
#IBAction func targetTouchAction(_ sender: Any) {
let images: [UIImage] = (1...10).map { return UIImage(named: "Jump_\($0)")! }
self.jackImage.frame.origin.y = self.jackImage.frame.origin.y + 100.0
self.jackImage.animationImages = images
self.jackImage.animationDuration = 2.0
self.jackImage.animationRepeatCount = 1
self.jackImage.startAnimating()
}
I am trying this from last two three hours but no luck.
You are mixing 2 different types of animation. Don't do that. Using the animationImages property of a UIImageView is separate from using UIView animation methods like UIView.animate(duration:animations:)
Get rid of that UIView animation wrapper, and just specify the animation images and other settings for your image view:
#IBAction func targetTouchAction(_ sender: Any) {
let jumpImages = ["Jump_1","Jump_2","Jump_3","Jump_4","Jump_5","Jump_6","Jump_7","Jump_8","Jump_9","Jump_10"]
var images = [UIImage]()
for image in jumpImages{
images.append(UIImage(named: image)!)
}
self.imageView.frame.origin.y = self.imageView.frame.origin.y + 100.0
self.imageView.animationImages = images
self.imageView.animationDuration = 2.0
self.imageView.animationRepeatCount = 1
self.imageView.startAnimating()
}
Note that loading the array of images into the image view each time you trigger the animation is unnecessary, but it should still work.
I haven't worked with SpriteKit, so I'm not sure how your image view animation will interact with that. (Plus you didn't show that part of your code.)
Also, note that you could create your array of images with 1 line of code, and without using a hard-coded array of filenames:
let images: [UIImage] = (1...10).map { return UIImage(named: "Jump_\($0)") }
That code creates a sequence from 1 to 10. It then uses the map statement to map that sequence into an array of images by feeding the value into a string, and using that string as the image name in a call to UIImage(named:)
I've attempted this multiple times, 1st by just trying to add the labels under my sliders (see picture below), but labels do not support integers. My newest attempt used 4 integer variables and set the label value to it, the only thing wrong with this method is it only works with one label, if I do this for all 4 I cannot add them together. `
var aValue: Int {
didSet {
mathCriAValue.text = "\(aValue)"
}
}
#IBAction func mathCriAChanged( sender: UISlider) {
aValue = Int(sender.value)
}
Main storyboard
Create a reference to each of your sliders and each of your labels (i.e. make them all IBOutlet properties).
When your slider event is triggered, check which slider is the sender and update the text in the appropriate label:
labelA.text = "\(sliderA.value)"
Sum up the values of all sliders:
let total = sliderA.value + sliderB.value + sliderC.value + sliderD.value
Set the text in the total label (to which you also need a reference):
totalLabel.text = "\(total)"
In my app I'm allowing the user the change some of the UI elements based on color. So, I have three versions of an image which can be used for a button and I'd like to select the image programmatically:
PSEUDO CODE
"image0", "image1", "image3"
var userChoice:integer
myButton.setImage("myImage"+userChoice , .normal)
I've seen this solution in SO:
Programmatically access image assets
What would be the Swift equivalent code?
Right now I'm using image literal:
self.But_Settings.setImage(#imageLiteral(resourceName: "settingswhite"), for: UIControlState.normal)
but of course Xcode changes this part "#imageLiteral(resourceName: "settingswhite")" to an icon which cannot be edited.
Then don't use image literal. Image literals are just that - a hard value in code that you can't change during run time. Load an image dynamically from your bundle:
if let image = UIImage(named: "myImage" + userChoice) {
self.But_Settings.setImage(image, for: .normal)
}
Do you think this would help? : But_Settings.setImage(UIImage(named: "play.png"), for: UIControlState.normal). Here you are using name of the asset
Since it's a limited number of choices it sounds like a good place for an enum.
enum ImageChoice: Int {
case zero = 0, one, two
var image: UIImage {
switch self {
case .zero:
return // Some Image, can use the icon image xcode provides now
case .one:
return //another image
case .two:
return //another image
}
}
}
Then you can easily get the correct image by initializing the enum by using an Int value.
guard let userChoice = ImageChoice(rawValue: someInt) else { return //Default Image }
let image = userChoice.image