I can get my buttons to hide, but not unhide.
I hide the answerOneCover button on tap with:
#IBAction func answerOneCoverTapped(_ sender: Any) {
animateButtonCoverOut(button: answerOneCover)
}
func animateButtonCoverOut(button: UIButton) {
UIView.animate(withDuration: 1.0, delay: 0.1, options:
UIViewAnimationOptions.curveEaseOut, animations: {
button.alpha = 0
}, completion: { finished in
button.isHidden = true
})
}
And I try to unhide the answerOneCover button when a different button, answerOneButtonText button is tapped:
#IBAction func answerOneButtonTextTapped(_ sender: Any) {
answerOneCover.isHidden = false
}
But I can't get answerOneCover to unhide. Is there any way to do this that I'm missing?
You have to set the buttons Alpha back to 1. change your code to look like this:
#IBAction func answerOneButtonTextTapped(_ sender: Any) {
answerOneCover.alpha = 1
answerOneCover.isHidden = false
}
OR you can put it in your animations completion like so:
func animateButtonCoverOut(button: UIButton) {
UIView.animate(withDuration: 1.0, delay: 0.1, options:
UIViewAnimationOptions.curveEaseOut, animations: {
button.alpha = 0
}, completion: { finished in
button.isHidden = true
button.alpha = 1
})
}
Related
I'am trying to animate the opacity of a AVPlayerLayer when a button is tapped. Here is my function :
#IBAction func boutonTapped(_ sender: UIButton) {
if(paused){
UIView.animate(withDuration: 5.0, animations: {
self.avPlayerLayer.opacity = 1.0
}, completion: nil)
//avPlayer.play()
}else{
UIView.animate(withDuration: 5.0, animations: {
self.avPlayerLayer.opacity = 0
}, completion:nil)
//avPlayer.pause()
}
paused = !paused
}
An opacity animation is launched but it is very speed (about 0.5s). I tried to change the duration for 10s and the animation is the same
I tried to add self.view.layoutIfNeeded() inside the animation block with no effect.
Have you any idea ? Thanks !
Instead of animating the opacity of avPlayerLayer, try animating the alpha of the customView where you're adding avPlayerLayer, i.e.
#IBAction func boutonTapped(_ sender: UIButton) {
UIView.animate(withDuration: 5.0) {
self.customView.alpha = paused ? 1.0 : 0.0 //here...
paused ? self.avPlayer.play() : self.avPlayer.pause()
}
paused = !paused
}
There is no need to call self.view.layoutIfNeeded().
You should change an animation code to change opacity of AVPlayerLayer as follow:
#IBAction func boutonTapped(_ sender: UIButton) {
UIView.transition(with: self.videoPlayerView, duration: 5.0, options: [.transitionCrossDissolve], animations: {
self.videoPlayerView.layer.sublayers?.first(where: { $0 is AVPlayerLayer })?.opacity = paused ? 1 : 0
}, completion: nil)
paused ? avPlayer.play() : avPlayer.pause()
}
videoPlayerView is view where you have added AVPlayerLayer instance.
I think you need to put self.view.layoutIfNeeded() inside animation block but not the opacity update code. Like this,
#IBAction func boutonTapped(_ sender: UIButton) {
if (paused) {
self.avPlayerLayer.opacity = 1.0
//avPlayer.play()
} else {
self.avPlayerLayer.opacity = 0
//avPlayer.pause()
}
UIView.animate(withDuration: 5.0, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
paused = !paused
}
Good day,
I seem to have such a simple problem but I just can not wrap my head around it.
I have a container view inside a view controller. In that container I have few labels. The container has its own view controller. In the view controller for the container I have a timer running and I want that label to show the timer. But every time I use that label the app crashes with
"Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value"
If I comment the line out that has this label then everything runs fine.
#IBOutlet weak var timeLabel: UILabel!
var counter = 0.0
var timer = Timer()
var isRunning = false
func startStopTimer () {
if isRunning {
timer.invalidate()
isRunning = false
}else {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
isRunning = true
}
}
#objc func updateTimer() {
counter = counter + 0.1
timeLabel.text = String(counter)
}
This is the first time I play around with container view in the Main storyboard.
Anyone that knows what I am doing wrong or has suggestion what I can try to change?
Thanks
Jonas
Full Code
class MainViewController: UIViewController {
#IBOutlet weak var topContainer: UIView!
#IBOutlet weak var informationContainer: UIView!
#IBOutlet weak var startStopButtonOutlet: UIButton!
let informationContainerVC = InformationContainerViewController()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
func setupView() {
topContainer.layer.cornerRadius = 5
topContainer.layer.masksToBounds = true
informationContainer.layer.cornerRadius = 5
informationContainer.layer.masksToBounds = true
startStopButtonOutlet.layer.cornerRadius = 5
startStopButtonOutlet.layer.masksToBounds = true
}
#IBAction func startStopButton_TouchUpInside(_ sender: UIButton) {
informationContainerVC.startStopTimer()
UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
sender.transform = CGAffineTransform.identity
}, completion: nil)
if informationContainerVC.isRunning {
startStopButtonOutlet.setTitle("Push to Pause", for: .normal)
}else {
startStopButtonOutlet.setTitle("Push to Start", for: .normal)
}
}
#IBAction func startStopButton_TouchDown(_ sender: UIButton) {
UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseIn], animations: {
sender.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
if self.informationContainerVC.isRunning {
sender.backgroundColor = UIColor.white.withAlphaComponent(0.5)
}else {
sender.backgroundColor = UIColor.green.withAlphaComponent(0.8)
}
}, completion: nil)
}
#IBAction func startStopButton_TouchUpOutside(_ sender: UIButton) {
UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
sender.transform = CGAffineTransform.identity
}, completion: nil)
}
}
Here is the code for the container view controller
class InformationContainerViewController: UIViewController {
#IBOutlet weak var timeLabel: UILabel!
var counter = 0.0
var timer = Timer()
var isRunning = false
func startStopTimer () {
if isRunning {
timer.invalidate()
isRunning = false
}else {
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
isRunning = true
}
}
#objc func updateTimer() {
counter = counter + 0.1
timeLabel.text = String(counter)
}
}
When you say let informationContainerVC = InformationContainerViewController() you are creating a new instance of InformationContainerViewController that is not linked to the storyboard, so none of the outlets are set.
You need to get a reference to the view controller instance that is actually in your container view. You can do this in prepare(for segue:); If you look at your storyboard you will see that there is an embed segue that links your containing view controller to the contained view controller.
In your MainViewController:
var informationContainerVC: InformationContainerViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destVC = segue.destination as? InformationContainerViewController {
self.informationContainerVC = destVC
}
}
#IBAction func startStopButton_TouchUpInside(_ sender: UIButton) {
informationContainerVC?.startStopTimer()
UIButton.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
sender.transform = CGAffineTransform.identity
}, completion: nil)
if informationContainerVC?.isRunning {
startStopButtonOutlet.setTitle("Push to Pause", for: .normal)
} else {
startStopButtonOutlet.setTitle("Push to Start", for: .normal)
}
}
Now you will have a reference to the correct view controller instance
I have a UIView EmptyCollectionView, which I display when my UICollectionView is empty. The way I have this working is that I create the UIView and addSubview in viewDidLoad of my ViewController, then change toggle isHidden property of the view (as well as the collectionview) as needed.
I'd like to polish things up a little now I have the core function working, and I wan't to add some subtle animation to the subviews contained in my empty view, such as making the contained imageview bounce on display.
So my question is, what is the best way to detect when the UIView is being shown (i.e. is there a viewDidAppear type callback I could use)?
Supplementary question: I'm new to this... Is adding the empty view and toggling the isHidden property a good way of doing this? Or should I be doing it a different way? (i.e. should I instead be creating and destroying the view as needed, rather than keeping it around)
Thanks
The best way in my opinion is to extend UIView
extension UIView {
func fadeIn(_ duration: TimeInterval = 0.2, onCompletion: (() -> Void)? = nil) {
self.alpha = 0
self.isHidden = false
UIView.animate(withDuration: duration,
animations: { self.alpha = 1 },
completion: { (value: Bool) in
if let complete = onCompletion { complete() }
}
)
}
func fadeOut(_ duration: TimeInterval = 0.2, onCompletion: (() -> Void)? = nil) {
UIView.animate(withDuration: duration,
animations: { self.alpha = 0 },
completion: { (value: Bool) in
self.isHidden = true
if let complete = onCompletion { complete() }
}
)
}
}
So you just have to call view.fadeIn() for a default 0.2 sec animation, or view.fadeIn(1) to make it last one second.
You can even add a completion event:
view.fadeOut(0.5, onCompletion: {
print("Animation completed, do whatever you want")
})
This works, I hope it can help you. To hide view:
UIView.animate(withDuration: 0.3/*Animation Duration second*/, animations: {
self.EmptyCollectionView.alpha = 0
}, completion: {
(value: Bool) in
self.EmptyCollectionView.isHidden = true
})
To show view:
self.EmptyCollectionView.isHidden = false
UIView.animate(withDuration: 0.3, animations: {
self.EmptyCollectionView.alpha = 1
}, completion: nil)
Swift 4.2 extension to allow animation when setting isHidden on any UIView class:
extension UIView {
func setIsHidden(_ hidden: Bool, animated: Bool) {
if animated {
if self.isHidden && !hidden {
self.alpha = 0.0
self.isHidden = false
}
UIView.animate(withDuration: 0.25, animations: {
self.alpha = hidden ? 0.0 : 1.0
}) { (complete) in
self.isHidden = hidden
}
} else {
self.isHidden = hidden
}
}
}
You can animate the alpha property of EmptyCollectionView to either 0 to hide or 1 to show
UIView.animate(withDuration: 0.5) {
self.EmptyCollectionView.alpha = 0
}
Also make sure that isOpaque property is set to False to enable Transparency of the view
Swift 5
import UIKit
extension UIView {
func animateSetHidden(_ hidden: Bool, duration: CGFloat = CATransaction.animationDuration(), completion: #escaping (Bool)->() = { _ in}) {
if duration > 0 {
if self.isHidden && !hidden {
self.alpha = 0
self.isHidden = false
}
UIView.animate(withDuration: duration, delay:0, options: .beginFromCurrentState) {
self.alpha = hidden ? 0 : 1
} completion: { c in
if c {
self.isHidden = hidden
}
completion(c)
}
} else {
self.isHidden = hidden
self.alpha = hidden ? 0 : 1
completion(true)
}
}
}
I'm trying to create a basic animation. I need to touch on a button to hide or show.
I wrote this code to tap on the screen:
func visibleControlButton(_ sender: UITapGestureRecognizer) {
if (backButton!.isHidden) {
_UIButtonHiddenAnimation.hiddenAnimation(button: self.backButton!, hide: false)
} else {
_UIButtonHiddenAnimation.hiddenAnimation(button: self.backButton!, hide: true)
}
}
Definition _UIButtonHiddenAnimation:
class _UIButtonHiddenAnimation {
class func hiddenAnimation(button: UIButton, hide: Bool) {
UIView.animate(withDuration: 0.2,
animations: {
hide ? (button.alpha = 0) : (button.alpha = 1.0)
},
completion: {
finished in hide ? (button.isHidden = true) : (button.isHidden = false)
})
}
}
Animates just hide the button. How to make an animated appearance of a button?
The problem is that if the button is hidden, you are animating the alpha to 1 but we cannot see that — because the button is hidden! Then you set isHidden to false and the button jumps into view.
The solution: forget all about isHidden and change only the alpha — and then change your if test to match what you are doing with the button, i.e. simply test against its alpha value. Thus (neatening things up as we go):
class _UIButtonHiddenAnimation {
class func hiddenAnimation(button: UIButton, hide: Bool) {
UIView.animate(withDuration: 0.2, animations: {
button.alpha = hide ? 0 : 1.0
})
}
}
func visibleControlButton(_ sender: UITapGestureRecognizer) {
_UIButtonHiddenAnimation.hiddenAnimation(
button: self.backButton!, hide: backButton!.alpha > 0.1)
}
I am trying to animate a UIView on button click.
It does appear on first click but only after that.
#IBAction func viewDetails(sender: AnyObject) {
UIView.animateWithDuration(0.5 as NSTimeInterval, animations: {
println(self.viewDetailsView.center.x)
println(self.viewDetailsView.hidden)
self.viewDetailsView.hidden = false
self.viewDetailsView.center = CGPointMake(self.viewDetailsView.center.x - 4000, self.viewDetailsView.center.y)
self.view.layoutIfNeeded()
}, completion: {
finished in
self.detailsVisible = true
}) }
Trying this:
#IBAction func viewDetails(sender: AnyObject) {
println(self.viewDetailsView.center.x)
println(self.viewDetailsView.hidden)
self.viewDetailsView.hidden = false
self.viewDetailsView.center = CGPointMake(self.viewDetailsView.center.x - 4000, self.viewDetailsView.center.y)
UIView.animateWithDuration(0.5 as NSTimeInterval, animations: {
self.view.layoutIfNeeded()
}, completion: { finished in
self.detailsVisible = true
})
}