Micro
Micro

Reputation: 10891

Fade image of button from one image to another via a float value

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

Answers (3)

agibson007
agibson007

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

Here is the result: slidegif

Upvotes: 1

Vinaykrishnan
Vinaykrishnan

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)!
}

enter image description here

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

Mitesh Dobareeya
Mitesh Dobareeya

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

enter image description here

Upvotes: 0

Related Questions