Swiftycam media capture library delegate crashes - ios

I am using this library called SwiftyCam As it is mentioned in its page, this part is a bit confusing:
SwiftyCam is a drop-in convenience framework. To create a Camera instance, create a new UIViewController subclass. Replace the UIViewController subclass declaration with SwiftyCamViewController.
So i created a new view controller extends class SwiftyCameraViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate as in sample project. And i called this class from my main UIViewcontroller(MainViewController.swift) as:
let swiftyCamera = SwiftyCameraViewController()
self.present(swiftyCamera, animated: true, completion: nil)
So, this is SwiftyCameraViewController:
import UIKit
class SwiftyCameraViewController: SwiftyCamViewController, SwiftyCamViewControllerDelegate {
#IBOutlet weak var captureButton: SwiftyRecordButton!
#IBOutlet weak var flipCameraButton: UIButton!
#IBOutlet weak var flashButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
cameraDelegate = self
maximumVideoDuration = 10.0
shouldUseDeviceOrientation = true
allowAutoRotate = true
audioEnabled = true
}
override var prefersStatusBarHidden: Bool {
return true
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
captureButton.delegate = self
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didTake photo: UIImage) {
let newVC = PhotoViewController(image: photo)
self.present(newVC, animated: true, completion: nil)
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didBeginRecordingVideo camera: SwiftyCamViewController.CameraSelection) {
print("Did Begin Recording")
captureButton.growButton()
UIView.animate(withDuration: 0.25, animations: {
self.flashButton.alpha = 0.0
self.flipCameraButton.alpha = 0.0
})
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFinishRecordingVideo camera: SwiftyCamViewController.CameraSelection) {
print("Did finish Recording")
captureButton.shrinkButton()
UIView.animate(withDuration: 0.25, animations: {
self.flashButton.alpha = 1.0
self.flipCameraButton.alpha = 1.0
})
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFinishProcessVideoAt url: URL) {
let newVC = VideoViewController(videoURL: url)
self.present(newVC, animated: true, completion: nil)
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFocusAtPoint point: CGPoint) {
let focusView = UIImageView(image: #imageLiteral(resourceName: "focus"))
focusView.center = point
focusView.alpha = 0.0
view.addSubview(focusView)
UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseInOut, animations: {
focusView.alpha = 1.0
focusView.transform = CGAffineTransform(scaleX: 1.25, y: 1.25)
}, completion: { (success) in
UIView.animate(withDuration: 0.15, delay: 0.5, options: .curveEaseInOut, animations: {
focusView.alpha = 0.0
focusView.transform = CGAffineTransform(translationX: 0.6, y: 0.6)
}, completion: { (success) in
focusView.removeFromSuperview()
})
})
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didChangeZoomLevel zoom: CGFloat) {
print(zoom)
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didSwitchCameras camera: SwiftyCamViewController.CameraSelection) {
print(camera)
}
func swiftyCam(_ swiftyCam: SwiftyCamViewController, didFailToRecordVideo error: Error) {
print(error)
}
#IBAction func cameraSwitchTapped(_ sender: Any) {
switchCamera()
}
#IBAction func toggleFlashTapped(_ sender: Any) {
flashEnabled = !flashEnabled
if flashEnabled == true {
flashButton.setImage(#imageLiteral(resourceName: "flash"), for: UIControlState())
} else {
flashButton.setImage(#imageLiteral(resourceName: "flashOutline"), for: UIControlState())
}
}
}
It crashed at line 33: captureButton.delegate = self, because captureButton is nil
I appreciate any kind of help. Thank you.

You must load the viewController with identifier
let swiftyCamera = self.storyboard?.instantiateViewController(withIdentifier:"swiftyCameraID")
self.present(swiftyCamera, animated: true, completion: nil)

Related

Animating UIButton configuration change

Modern UIButton configuration API allows for new way of setting button appearance. However the code below skips the animation entirely.
#IBAction func buttonTouched(_ sender: UIButton) {
sender.configuration?.background.backgroundColor = .green
UIView.animate(withDuration: 0.4, delay: 0.5) {
sender.configuration?.background.backgroundColor = .systemMint
}
}
Similar thing can be done like this:
#IBAction func buttonTouched(_ sender: UIButton) {
sender.backgroundColor = .red
UIView.animate(withDuration: 0.4, delay: 0.5) {
sender.backgroundColor = .systemMint
}
}
And this works. The question is how to animate UIButton's configuration changes.
After some quick searching, it appears configuration.background.backgroundColor is not animatable.
Depending on your needs, you can use a .customView for the button's background and then animate the color change for that view.
Quick example (assuming you've added the button as an #IBOutlet):
class TestVC: UIViewController {
#IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
let v = UIView()
v.backgroundColor = .red
button.configuration?.background.customView = v
}
#IBAction func buttonTouched(_ sender: UIButton) {
if let v = sender.configuration?.background.customView {
UIView.animate(withDuration: 0.4, delay: 0.5) {
v.backgroundColor = v.backgroundColor == .red ? .systemMint : .red
}
}
}
}
The way to achieve animated configuration change by using transitions is the only workaround I could find so far. Somewhat like this:
#IBAction func buttonTouched(_ sender: UIButton) {
UIView.transition(with: sender, duration: 0.3, options: .transitionCrossDissolve) {
sender.configuration?.background.backgroundColor = .red
} completion: { _ in
UIView.transition(with: sender, duration: 1.0, options: .transitionCrossDissolve) {
sender.configuration?.background.backgroundColor = .cyan
}
}
}
When I tried to optimize and reuse code, I ended with something like:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Another option is subclass `UIButton` and override its `configurationUpdateHandler`
view.subviews.compactMap({ $0 as? UIButton }).forEach {
$0.configurationUpdateHandler = { button in
guard let config = button.configuration else { return }
button.setConfiguration(config,duration: 2)
}
}
}
#IBAction func buttonTouched(_ sender: UIButton) {
// sender.configuration?.background.backgroundColor = .red
// sender.configuration?.baseForegroundColor = .white
// The above would work, but we should rather aggregate all changes at once.
if var config = sender.configuration {
config.background.backgroundColor = .red
config.baseForegroundColor = .white
sender.configuration = config
}
}
}
extension UIButton {
func setConfiguration(_ configuration: UIButton.Configuration, duration: Double = 0.25, completion: ((Bool) -> Void)? = nil) {
UIView.transition(with: self, duration: duration, options: .transitionCrossDissolve) {
self.configuration? = configuration
} completion: { completion?($0) }
}
}
I

Swift: Instantiate a view controller for custom transition in the current navigation stack

Introduction
I'm creating an app that has, in its rootViewController, a UITableView and a UIPanGestureRecognizer attached to a small UIView acting as a "handle" which enables a custom view controller transition for a UIViewController called "SlideOutViewController" to be panned from the right.
Issue
I have noticed two issues with my approach. But the actual custom transition works as expected.
When the SlideOutViewController is created it is not attached to the navigation stack I believe, therefore it has no associated navigationBar. And if I use the navigationController to push it on the stack, I loose the interactive transition.
Side note: I have not found a way to connect the handle to the SlideOutViewController that is interactively dragged out. So the translation of the handle is not consistent with the SlideOutViewControllers position.
Question
How can I add the SlideOutViewController to the navigation stack? So that the SlideOutViewController transitions with a navigationBar when I trigger the UIPanGestureRecognizer?
My code
In the rootViewController.
class RootViewController: UIViewController {
...
let slideControllerHandle = UIView()
var interactionController : UIPercentDrivenInteractiveTransition?
override func viewDidLoad() {
super.viewDidLoad()
... // Setting up the table view etc...
setupPanGForSlideOutController()
}
private func setupPanGForSlideOutController() {
slideControllerHandle.translatesAutoresizingMaskIntoConstraints = false
slideControllerHandle.layer.borderColor = UIColor.black.cgColor
slideControllerHandle.layer.borderWidth = 1
slideControllerHandle.layer.cornerRadius = 30
view.addSubview(slideControllerHandle)
slideControllerHandle.frame = CGRect(x: view.frame.width - 12.5, y: view.frame.height / 2, width: 25, height: 60)
let panGestureForCalendar = UIPanGestureRecognizer(target: self, action: #selector(handlePanGestureForSlideOutViewController(_:)))
slideControllerHandle.addGestureRecognizer(panGestureForCalendar)
}
#objc private func handlePanGestureForSlideOutViewController(_ gesture: UIPanGestureRecognizer) {
let xPosition = gesture.location(in: view).x
let percent = 1 - (xPosition / view.frame.size.width)
switch gesture.state {
case .began:
guard let slideOutController = storyboard?.instantiateViewController(withIdentifier: "CNSlideOutViewControllerID") as? SlideOutViewController else { fatalError("Sigh...") }
interactionController = UIPercentDrivenInteractiveTransition()
slideOutController.customTransitionDelegate.interactionController = interactionController
self.present(slideOutController, animated: true)
case .changed:
slideControllerHandle.center = CGPoint(x: xPosition, y: slideControllerHandle.center.y)
interactionController?.update(percent)
case .ended, .cancelled:
let velocity = gesture.velocity(in: view)
interactionController?.completionSpeed = 0.999
if percent > 0.5 || velocity.x < 10 {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.slideControllerHandle.center = CGPoint(x: self.view.frame.width, y: self.slideControllerHandle.center.y)
})
interactionController?.finish()
} else {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.5, options: .curveEaseInOut, animations: {
self.slideControllerHandle.center = CGPoint(x: -25, y: self.slideControllerHandle.center.y)
})
interactionController?.cancel()
}
interactionController = nil
default:
break
}
}
The SlideOutViewController
class SlideOutViewController: UIViewController {
var interactionController : UIPercentDrivenInteractiveTransition?
let customTransitionDelegate = TransitionDelegate()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
modalPresentationStyle = .custom
transitioningDelegate = customTransitionDelegate
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .red
navigationItem.title = "Slide Controller"
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addNewData(_:)))
navigationItem.setRightBarButton(addButton, animated: true)
}
}
The custom transition code. Based on Rob's descriptive answer on this SO question
TransitionDelegate
class TransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
weak var interactionController : UIPercentDrivenInteractiveTransition?
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return CNRightDragAnimationController(transitionType: .presenting)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return CNRightDragAnimationController(transitionType: .dismissing)
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return PresentationController(presentedViewController: presented, presenting: presenting)
}
func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactionController
}
func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactionController
}
}
DragAnimatedTransitioning
class CNRightDragAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
enum TransitionType {
case presenting
case dismissing
}
let transitionType: TransitionType
init(transitionType: TransitionType) {
self.transitionType = transitionType
super.init()
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let inView = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
let fromView = transitionContext.view(forKey: .from)!
var frame = inView.bounds
switch transitionType {
case .presenting:
frame.origin.x = frame.size.width
toView.frame = frame
inView.addSubview(toView)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
toView.frame = inView.bounds
}, completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
case .dismissing:
toView.frame = frame
inView.insertSubview(toView, belowSubview: fromView)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
frame.origin.x = frame.size.width
fromView.frame = frame
}, completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
}
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
}
PresentationController
class PresentationController: UIPresentationController {
override var shouldRemovePresentersView: Bool { return true }
}
Thanks for reading my question.
The animation code you’ve taken this from is for custom “present” (e.g. modal) transitions. But if you want a custom navigation as you push/pop when using a navigation controller, you specify a delegate for your UINavigationController and then return the appropriate transitioning delegate in navigationController(_:animationControllerFor:from:to:). And also implement navigationController(_:interactionControllerFor:) and return your interaction controller there.
E.g. I'd do something like:
class FirstViewController: UIViewController {
let navigationDelegate = CustomNavigationDelegate()
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.delegate = navigationDelegate
navigationDelegate.addPushInteractionController(to: view)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationDelegate.pushDestination = { [weak self] in
self?.storyboard?.instantiateViewController(withIdentifier: "Second")
}
}
}
Where:
class CustomNavigationDelegate: NSObject, UINavigationControllerDelegate {
var interactionController: UIPercentDrivenInteractiveTransition?
var current: UIViewController?
var pushDestination: (() -> UIViewController?)?
func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationController.Operation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return CustomNavigationAnimator(transitionType: operation)
}
func navigationController(_ navigationController: UINavigationController,
interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactionController
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
current = viewController
}
}
// MARK: - Push
extension CustomNavigationDelegate {
func addPushInteractionController(to view: UIView) {
let swipe = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handlePushGesture(_:)))
swipe.edges = [.right]
view.addGestureRecognizer(swipe)
}
#objc private func handlePushGesture(_ gesture: UIScreenEdgePanGestureRecognizer) {
guard let pushDestination = pushDestination else { return }
let position = gesture.translation(in: gesture.view)
let percentComplete = min(-position.x / gesture.view!.bounds.width, 1.0)
switch gesture.state {
case .began:
interactionController = UIPercentDrivenInteractiveTransition()
guard let controller = pushDestination() else { fatalError("No push destination") }
current?.navigationController?.pushViewController(controller, animated: true)
case .changed:
interactionController?.update(percentComplete)
case .ended, .cancelled:
let speed = gesture.velocity(in: gesture.view)
if speed.x < 0 || (speed.x == 0 && percentComplete > 0.5) {
interactionController?.finish()
} else {
interactionController?.cancel()
}
interactionController = nil
default:
break
}
}
}
// MARK: - Pop
extension CustomNavigationDelegate {
func addPopInteractionController(to view: UIView) {
let swipe = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handlePopGesture(_:)))
swipe.edges = [.left]
view.addGestureRecognizer(swipe)
}
#objc private func handlePopGesture(_ gesture: UIScreenEdgePanGestureRecognizer) {
let position = gesture.translation(in: gesture.view)
let percentComplete = min(position.x / gesture.view!.bounds.width, 1)
switch gesture.state {
case .began:
interactionController = UIPercentDrivenInteractiveTransition()
current?.navigationController?.popViewController(animated: true)
case .changed:
interactionController?.update(percentComplete)
case .ended, .cancelled:
let speed = gesture.velocity(in: gesture.view)
if speed.x > 0 || (speed.x == 0 && percentComplete > 0.5) {
interactionController?.finish()
} else {
interactionController?.cancel()
}
interactionController = nil
default:
break
}
}
}
And
class CustomNavigationAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let transitionType: UINavigationController.Operation
init(transitionType: UINavigationController.Operation) {
self.transitionType = transitionType
super.init()
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let inView = transitionContext.containerView
let toView = transitionContext.view(forKey: .to)!
let fromView = transitionContext.view(forKey: .from)!
var frame = inView.bounds
switch transitionType {
case .push:
frame.origin.x = frame.size.width
toView.frame = frame
inView.addSubview(toView)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
toView.frame = inView.bounds
}, completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
case .pop:
toView.frame = frame
inView.insertSubview(toView, belowSubview: fromView)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
frame.origin.x = frame.size.width
fromView.frame = frame
}, completion: { finished in
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
})
case .none:
break
}
}
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.5
}
}
Then, if the second view controller wanted to have the custom interactive pop plus the ability to swipe to the third view controller:
class SecondViewController: UIViewController {
var navigationDelegate: CustomNavigationDelegate { return navigationController!.delegate as! CustomNavigationDelegate }
override func viewDidLoad() {
super.viewDidLoad()
navigationDelegate.addPushInteractionController(to: view)
navigationDelegate.addPopInteractionController(to: view)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationDelegate.pushDestination = { [weak self] in
self?.storyboard?.instantiateViewController(withIdentifier: "Third")
}
}
}
But if the last view controller can't push to anything, but only pop:
class ThirdViewController: UIViewController {
var navigationDelegate: CustomNavigationDelegate { return navigationController!.delegate as! CustomNavigationDelegate }
override func viewDidLoad() {
super.viewDidLoad()
navigationDelegate.addPopInteractionController(to: view)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationDelegate.pushDestination = nil
}
}

Change ViewController after animation

I have created this animation for the first screen of the app(I'm not using Launchscreen) but when the animation ends I don't know how to pass to the next view controller. I've tired by segue but nothing :/
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var logoLSMini: UIImageView!
#IBOutlet weak var logoLSMini2: UIImageView!
#IBOutlet weak var logoLS: UIImageView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.logoLSMini.alpha = 0.0
self.logoLSMini2.alpha = 0.0
self.logoLS.alpha = 0.0
self.logoLS.frame.origin.y = +100
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 5, delay: 0.0, options: .curveEaseOut , animations: {
//FIRST EFFECT
self.logoLSMini.alpha = 1.0
self.logoLSMini.transform = CGAffineTransform(rotationAngle: 360)
self.logoLSMini.transform = CGAffineTransform(scaleX: 100, y: 100)
self.logoLS.alpha = 1.0
}, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
You simply need to perform the segue in the completion of UIView.animate. Just make sure you substitute whatever identifier you added to your segue in Storyboard for yourSegue.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIView.animate(withDuration: 5, delay: 0.0, options: .curveEaseOut , animations: {
//FIRST EFFECT
self.logoLSMini.alpha = 1.0
self.logoLSMini.transform = CGAffineTransform(rotationAngle: 360)
self.logoLSMini.transform = CGAffineTransform(scaleX: 100, y: 100)
self.logoLS.alpha = 1.0
}, completion: { _ in
self.performSegue(withIdentifier: "yourSegue", sender: nil)
})
}
Try to put the code of moving viewController in the completionHandler
UIView.animate(withDuration: 5, delay: 0.0, options: .curveEaseOut, animations: {
.....
}, completion: { (finished) in
if finished {
//Move to your next controller
DispatchQueue.main.async {
//Your code
}
}
})

Animation stops working when view appears again

extension UIView {
func startBlinking() {
UIView.animate(withDuration: 0.8, delay: 0.0, options: [.allowUserInteraction, .curveEaseInOut, .autoreverse, .repeat], animations: { self.alpha = 0 }, completion: nil)
}
}
How do I use it?
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
monthLabel.startBlinking()
}
When method is called first time, then it blinks... but the second time when view did appear the label disappears and... that's it.
Why doesn't it work again?
My logs:
did load
did appear
start blinking
did appear
start blinking
Try:
import UIKit
protocol Then {}
extension Then {
func then(_ block: (Self) -> Void) -> Self {
block(self)
return self
}
}
extension UIView: Then {}
class ViewController: UIViewController {
private var animate: ((Bool) -> Void)?
private var canAnimate: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
let label = UILabel().then {
$0.text = "Hello World!"
$0.textColor = .black
$0.translatesAutoresizingMaskIntoConstraints = false
}
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
animate = { [weak self] (forward) in
UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 1.0, delay: 0.0, options: [.curveLinear, .autoreverse, .repeat], animations: {
label.alpha = forward ? 0.0 : 1.0
}, completion: { [weak self] _ in
if self?.canAnimate ?? true {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25, execute: {
self?.animate?(!forward)
})
}
}).startAnimation()
}
animate?(true)
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
let controller = UIViewController()
self.navigationController?.pushViewController(controller, animated: true)
}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
canAnimate = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
canAnimate = true
animate?(true)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You need to restart the alpha
func startBlinking() {
self.layer.removeAllAnimations()
self.alpha = 1.0
UIView.animate(withDuration: 0.8, delay: 0.0, options: [.allowUserInteraction, .curveEaseInOut], animations: { self.alpha = 0.0 }, completion: nil)
}
using CABasicAnimation solves my issue
let animation = CABasicAnimation(keyPath: "opacity")
animation.isRemovedOnCompletion = false
animation.fromValue = 1
animation.toValue = 0.1
animation.duration = 0.8
animation.autoreverses = true
animation.repeatCount = Float.infinity
animation.beginTime = 0.0
yourView.layer.add(animation, forKey: nil)

Animate stop when change uiviewcontroller

I write marquee text for first view controller but change the controller and back the first view controller marquee text is not working.
First Controller Code:
#IBOutlet weak var marqueeText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
UIView.animate(withDuration: 16.0, delay: 1, options: ([.curveLinear, .repeat]), animations: {() -> Void in
marqueeText.center = CGPoint(x: 0 -marqueeText.center.bounds.size.width / 2, y: text.center.y)
}, completion: { _ in })
}
Please check the below code :
#IBOutlet weak var marqueeText: UILabel!
var marqueeTextPoint = CGPoint()
var stopAnim: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
marqueeTextPoint = marqueeText.center
marquee(text: marqueeText)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.marqueeText.center = self.marqueeTextPoint
marquee(text: marqueeText)
}
override func viewWillDisappear(_ animated: Bool) {
stopAnim = true
}
func marquee (text: UILabel) {
UIView.animate(withDuration: 16.0, delay: 1, options: ([.curveLinear, .repeat]), animations: {
text.center = CGPoint(x: 0 - text.bounds.size.width / 2, y: text.center.y)
}, completion: { _ in
if !(self.stopAnim) {
self.marquee(text: text)
} else {
text.layer.removeAllAnimations()
}
})
}

Resources