How to use a button to add 4 slider values together? - swift

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)"

Related

Programmatically Adding/Removing Images to Subview in Swift

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)

Move and Jump animation for UIImageView : Swift 4

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:)

Swift: Using Int in UILabel inside View Controller

I've set up an if statement which does things depending on an int value stored in a UILabel, however, my code can't determine the value of the int inside the label.
This is because the if statement runs within the viewdidload function. I'm basically looking for how I can pass the label value to my view. I'm struggling to make it work.
Here's the code:
override func viewDidLoad()
{
// If statement
var NumberRead = Int(Number.text!)
if NumberRead! <= 2 {
Picture.image = Pic1
} else {
Picture.image = Pic2
}
}
#IBOutlet weak var Number: UILabel!
Any suggestions for better ways to handle this would be amazing.
Thanks
I don't think the problem is that you use this code in viewDidLoad, but that your UILabel is empty when you run the code and the code is unwrapping a nil value. You have to set the UILabel Number to a value before you use the if statement.
I don't know what value you expect in the Number label, but either set it with an initial value, e.g. 0, or when this view controller is called through segueing from another view controller pass on the value the label should have. The code should then work fine.
How about:
set the default image to pic2, then use optional binding to check the value
Picture.image = Pic2
if let numTxt = Number.text {
if let num = Int(numTxt) {
if num <= 2 {
Picture.image = Pic1
}
}
}
You should separate your data and logic from the view. It is absurd to put a value into a label and try to interpret it. Please consider reading up on the MVC (model view controller) pattern which is the underpinning of iOS.
Your view controller should have a variable, say number to keep track of the value that determines which image to show.
var number: Int = 0 {
didSet {
imageView.image = number <= 2 ? pic1 : pic2
label.text = "\(number)"
}
}
On naming
Your variable names are also a mess. By convention variables are lowerCamelCase. If you are naming an UIImageView, the name picture is too generic and could be misleading. Also avoid names like pic1, pic2, better is something like activeImage, inactiveImage.

how to change image of one button by pressing other buttons?

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.

iOS how to make slider stop at discrete points

I would like to make a slider stop at discrete points that represent integers on a timeline. What's the best way to do this? I don't want any values in between. It would be great if the slider could "snap" to position at each discrete point as well.
The steps that I took here were pretty much the same as stated in jrturton's answer but I found that the slider would sort of lag behind my movements quite noticeably. Here is how I did this:
Put the slider into the view in Interface Builder.
Set the min/max values of the slider. (I used 0 and 5)
In the .h file:
#property (strong, nonatomic) IBOutlet UISlider *mySlider;
- (IBAction)sliderChanged:(id)sender;
In the .m file:
- (IBAction)sliderChanged:(id)sender
{
int sliderValue;
sliderValue = lroundf(mySlider.value);
[mySlider setValue:sliderValue animated:YES];
}
After this in Interface Builder I hooked up the 'Touch Up Inside' event for the slider to File's Owner, rather than 'Value Changed'. Now it allows me to smoothly move the slider and snaps to each whole number when my finger is lifted.
Thanks #jrturton!
UPDATE - Swift:
#IBOutlet var mySlider: UISlider!
#IBAction func sliderMoved(sender: UISlider) {
sender.setValue(Float(lroundf(mySlider.value)), animated: true)
}
Also if there is any confusion on hooking things up in the storyboard I have uploaded a quick example to github: https://github.com/nathandries/StickySlider
To make the slider "stick" at specific points, your viewcontroller should, in the valueChanged method linked to from the slider, determine the appropriate rounded from the slider's value and then use setValue: animated: to move the slider to the appropriate place. So, if your slider goes from 0 to 2, and the user changes it to 0.75, you assume this should be 1 and set the slider value to that.
What I did for this is first set an "output" variable of the current slider value to an integer (its a float by default). Then set the output number as the current value of the slider:
int output = (int)mySlider.value;
mySlider.value = output;
This will set it to move in increments of 1 integers. To make it move in a specific range of numbers, say for example, in 5s, modify your output value with the following formula. Add this between the first two lines above:
int output = (int)mySlider.value;
int newValue = 5 * floor((output/5)+0.5);
mySlider.value = newValue;
Now your slider "jumps" to multiples of 5 as you move it.
I did as Nathan suggested, but I also want to update an associated UILabel displaying the current value in real time, so here is what I did:
- (IBAction) countdownSliderChanged:(id)sender
{
// Action Hooked to 'Value Changed' (continuous)
// Update label (to rounded value)
CGFloat value = [_countdownSlider value];
CGFloat roundValue = roundf(value);
[_countdownLabel setText:[NSString stringWithFormat:#" %2.0f 秒", roundValue]];
}
- (IBAction) countdownSliderFinishedEditing:(id)sender
{
// Action Hooked to 'Touch Up Inside' (when user releases knob)
// Adjust knob (to rounded value)
CGFloat value = [_countdownSlider value];
CGFloat roundValue = roundf(value);
if (value != roundValue) {
// Almost 100% of the time - Adjust:
[_countdownSlider setValue:roundValue];
}
}
The drawback, of course, is that it takes two actions (methods) per slider.
Swift version with ValueChanged and TouchUpInside.
EDIT: Actually you should hook up 3 events in this case:
yourSlider.addTarget(self, action: #selector(presetNumberSliderTouchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])
I've just pasted my code, but you can easily see how it's done.
private func setSizesSliderValue(pn: Int, slider: UISlider, setSliderValue: Bool)
{
if setSliderValue
{
slider.setValue(Float(pn), animated: true)
}
masterPresetInfoLabel.text = String(
format: TexturingViewController.createAndSendPresetNumberNofiticationTemplate,
self.currentPresetNumber.name.uppercased(),
String(self.currentPresetNumber.currentUserIndexHumanFriendly)
)
}
#objc func presetNumberSliderTouchUp(_ sender: Any)
{
guard let slider = sender as? NormalSlider else{
return
}
setupSliderChangedValuesGeneric(slider: slider, setSliderValue: true)
}
private func setupSliderChangedValuesGeneric(slider: NormalSlider, setSliderValue: Bool)
{
let rounded = roundf((Float(slider.value) / Float(presetNumberStep))) * Float(presetNumberStep)
// Set new preset number value
self.currentPresetNumber.current = Int(rounded)
setSizesSliderValue(pn: Int(rounded), slider: slider, setSliderValue: setSliderValue)
}
#IBAction func presetNumberChanged(_ sender: Any)
{
guard let slider = sender as? NormalSlider else{
return
}
setupSliderChangedValuesGeneric(slider: slider, setSliderValue: false)
}