Reputation: 10891
In my use case, I have a slider that moves from 0.0 to 1.0. When moving that slider I want a button's image to fade from one image to another smoothly. The button will only transition between two images. As one fades in, the other fades out and vice-versa.
There are answers on SO on how to change the image of a button over a fixed duration but I can't find something based on a changing float.
So is there a way to change the image of a button over a duration from one image to another based on a float that changes from 0.0 to 1.0?
EDIT: For example, imagine a button that transitions smoothly from an image of a red star to a green star as you move the slider back and forth. (I know you could accomplish this other ways but I want to use two images)
Upvotes: 1
Views: 242
Reputation: 4393
Give this a shot. It is doing what you want I think. The trick is to set the layer speed to 0 and just update the timeOffset.
import UIKit
class ViewController: UIViewController {
lazy var slider : UISlider = {
let sld = UISlider(frame: CGRect(x: 30, y: self.view.frame.height - 60, width: self.view.frame.width - 60, height: 20))
sld.addTarget(self, action: #selector(sliderChanged), for: .valueChanged)
sld.value = 0
sld.maximumValue = 1
sld.minimumValue = 0
sld.tintColor = UIColor.blue
return sld
}()
lazy var button : UIButton = {
let bt = UIButton(frame: CGRect(x: 0, y: 60, width: 150, height: 150))
bt.center.x = self.view.center.x
bt.addTarget(self, action: #selector(buttonPress), for: .touchUpInside)
bt.setImage(UIImage(named: "cat1"), for: .normal)
return bt
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(button)
self.view.addSubview(slider)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
addAnimation()
}
func addAnimation(){
let anim = CATransition()
anim.type = kCATransitionFade
anim.duration = 1.0
button.layer.add(anim, forKey: nil)
button.layer.speed = 0
button.setImage(UIImage(named: "cat2"), for: .normal)
}
@objc func sliderChanged(){
print("value \(slider.value)")
button.layer.timeOffset = CFTimeInterval(slider.value)
}
@objc func buttonPress(){
print("pressed")
}
}
Upvotes: 1
Reputation: 768
This is another workaround, since i tired with single button but couldn't achieve the result, so what i did is i took two buttons overlaying each other, with same size, constraints and each with separate image.
var lastSlideValue : Float = 0.0
@IBOutlet weak var slideImage: UISlider!
@IBOutlet weak var btnImageOverlay: UIButton!
@IBOutlet weak var btnSecondOverlayImage: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
btnImageOverlay.imageView?.alpha = 1.0
btnSecondOverlayImage.imageView?.alpha = 0.0
}
@IBAction func sliderValueChanged(_ sender: Any) {//UIControlEventTouchUpInside connected method
let sliderr = sender as? UISlider
let value = sliderr?.value
if lastSlideValue < (sliderr?.value ?? 0.0) {
btnSecondOverlayImage.imageView?.alpha = CGFloat(value!)
btnImageOverlay.imageView?.alpha = 1 - CGFloat(value!)
} else if lastSlideValue == sliderr?.value {
print("equal")
} else {
btnImageOverlay.imageView?.alpha = CGFloat(value!)
btnSecondOverlayImage.imageView?.alpha = 1 - CGFloat(value!)
}
}
@IBAction func userTouchedSlider(_ sender: Any) { //UIControlEventValueChanged connected method
let sliderr = sender as? UISlider
lastSlideValue = (sliderr?.value)!
}
You could use cross fade animations with single button, but binding it with slider is difficult task. Let me know if you need any assistance with the same.
Upvotes: 0
Reputation: 1020
For Swift 4
//This is slider
@IBOutlet weak var mSlider: UISlider!
//Add Target for valueChanged in ViewDidLoad
self.mSlider.addTarget(self, action: #selector(ViewController.onLuminosityChange), for: UIControlEvents.valueChanged)
//called when value change
@objc func onLuminosityChange(){
let value = self.mSlider.value
print(value)
if value > 0.5 {
btnImage.imageView?.alpha = CGFloat(value)
UIView.transition(with: self.btnImage.imageView!,
duration:0.3,
options: .showHideTransitionViews,
animations: { self.btnImage.setImage(newImage, for: .normal) },
completion: nil)
}else{
btnImage.imageView?.alpha = 1 - CGFloat(value)
UIView.transition(with: self.btnImage.imageView!,
duration:0.3,
options: .showHideTransitionViews,
animations: { self.btnImage.setImage(oldImage, for: .normal) },
completion: nil)
}
}
Or Inset an Action directly via Storyboard/XIB
Upvotes: 0