UIView.animate Ignoring duration on custom pop I created. Swift 5 - ios

let bigView = UIViewController()
let pView = UIView()
extension UIViewController {
func showPopUp() {
bigView.modalPresentationStyle = .overFullScreen //or .overFullScreen for transparency
self.present(bigView, animated: false, completion: nil)
let bColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).withAlphaComponent(0.4)
blurView.frame = bigView.view.bounds
blurView.backgroundColor = bColor
bigView.view.addSubview(blurView)
pView.frame = CGRect(x: 0, y: 0, width: 300, height: 180)
if self.traitCollection.userInterfaceStyle == .light {
pView.backgroundColor = #colorLiteral(red: 0.9778117069, green: 0.9778117069, blue: 0.9778117069, alpha: 1) } else {pView.backgroundColor = #colorLiteral(red: 0.2506543464, green: 0.2506543464, blue: 0.2506543464, alpha: 1)}
pView.layer.cornerRadius = 15
pView.isOpaque = false
pView.center = blurView.center
blurView.addSubview(pView)
pView.transform = CGAffineTransform(scaleX: 1, y: 1)
pView.alpha = 0
UIView.animate(withDuration: 0.8, delay: 0.5, options: [], animations: {
pView.alpha = 1
pView.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
self.view.layoutIfNeeded()
}, completion: nil)
}
}
Hey guys here is a shortened version of my code, not sure why its not animating with a duration... when I click the button I have assigned it just jumps the scale to (scaleX: 1.1, y: 1.1).. instead of gradually animating. Any idea why ?

Related

NavBar title hidden behind CAGradientLayer

I would like to add gradient layer to my navbar, but after I add it, layer hides my title, like its behind that new sublayer.
override func viewDidLoad() {
super.viewDidLoad()
self.title = "My Trips"
self.navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
//self.navigationController?.navigationBar.layer.addSublayer(gradientLayer)
self.navigationController?.navigationBar.layer.insertSublayer(gradientLayer, at: 1)
setupGradient()
}
let gradientLayer = CAGradientLayer()
func setupGradient() {
gradientLayer.colors = [
UIColor(red: 0.259, green: 0.188, blue: 0.475, alpha: 1).cgColor,
UIColor(red: 0.11, green: 0.024, blue: 0.369, alpha: 1).cgColor
]
gradientLayer.locations = [0, 1]
gradientLayer.startPoint = CGPoint(x: 0.25, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
gradientLayer.transform = CATransform3DMakeAffineTransform(CGAffineTransform(a: 0, b: 0.58, c: -0.58, d: 0, tx: 0.5, ty: 0))
gradientLayer.bounds = (self.navigationController?.navigationBar.bounds.insetBy(dx: -0.01*view.bounds.size.width, dy: -1*view.bounds.size.height))!
}
Use this line for inserting layer.
self.navigationController?.navigationBar.subviews.first?.layer.insertSublayer(gradientLayer, at: 0)

Custom VC Transition not Dismissing Properly

I am trying to recreate the stock UIAlertAction in a VC with a custom transition. I currently have the presenting working perfectly(backgroundView fades in and the 'notification' VC slides from the bottom). The problem I am facing is when I dismiss the VC the backgroundView doesn't fade out. It's as if it's completely bypassing my animation block. Once completeTransition is called the backgroundView disappears completely. What is happening?
class AnimationController: NSObject {
let backgroundView = UIView()
}
extension AnimationController: UIViewControllerAnimatedTransitioning {
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
guard let toViewController = transitionContext.viewController(forKey: .to),
let fromViewController = transitionContext.viewController(forKey: .from) else {
transitionContext.completeTransition(false)
return
}
switch animationType {
case .present:
backgroundView.frame = CGRect(x: 0, y: 0, width: toViewController.view.frame.width, height: fromViewController.view.frame.height)
backgroundView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
backgroundView.alpha = 0
containerView.addSubview(backgroundView)
let viewToAnimate = toViewController.view!
containerView.addSubview(viewToAnimate)
toViewController.view.clipsToBounds = true
viewToAnimate.frame = CGRect(x: 0, y: viewToAnimate.frame.maxY, width: viewToAnimate.frame.width, height: viewToAnimate.frame.height)
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations: {
self.backgroundView.alpha = 1.0
viewToAnimate.transform = CGAffineTransform(translationX: 0, y: -viewToAnimate.frame.height)
}) { _ in
transitionContext.completeTransition(true)
}
case .dismiss:
containerView.addSubview(fromViewController.view!)
let testView = fromViewController.view!
backgroundView.frame = CGRect(x: 0, y: 0, width: testView.frame.width, height: testView.frame.height)
backgroundView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations: {
self.backgroundView.alpha = 0.0
testView.transform = CGAffineTransform(translationX: 0, y: testView.frame.height)
print("backgroundView Doesn't fade out")
}) { _ in
print("backgroundView disappears here")
transitionContext.completeTransition(true)
}
}
}
Your problem is that you're dealing with two separate instances of your AnimationController and hence two separate instances of backgroundView. One instance is instantiated for presentation and the other is instantiated for dismissal. Notice in your case .present: block you are calling containerView.addSubview(backgroundView) but you don't do the same in the case .dismiss: block. As a result, the backgroundView instance in the case .dismiss: block isn't even part of the view hierarchy.
What you need to do is call self.backgroundView.removeFromSuperview() in your first animation completion block. Then in your case .dismiss: you need to call containerView.addSubview(backgroundView) once again.
Try this...
switch animationType {
case .present:
// ...
containerView.addSubview(backgroundView)
// ...
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations: {
self.backgroundView.alpha = 1.0
viewToAnimate.transform = CGAffineTransform(translationX: 0, y: -viewToAnimate.frame.height)
}) { _ in
self.backgroundView.removeFromSuperview()
transitionContext.completeTransition(true)
}
case .dismiss:
// ...
containerView.addSubview(backgroundView)
containerView.addSubview(fromViewController.view!)
// ...
UIView.animate(withDuration: duration, delay: 0, usingSpringWithDamping: 0.80, initialSpringVelocity: 0.1, options: .curveEaseInOut, animations: {
self.backgroundView.alpha = 0.0
testView.transform = CGAffineTransform(translationX: 0, y: testView.frame.height)
print("backgroundView Doesn't fade out")
}) { _ in
print("backgroundView disappears here")
transitionContext.completeTransition(true)
}
}
you could try to present like this
//where DevolucionVC is you ViewController
if let controller = DevolucionVC() as? DevolucionVC {
if let window = self.window, let rootViewController = window.rootViewController {
var currentController = rootViewController
while let presentedController = currentController.presentedViewController {
currentController = presentedController
}
currentController.present(controller, animated: true, completion: nil)
}
}
you can dismiss it later by simply use
dismiss(animated: true, completion: nil)
Try This
for present replace this code
backgroundView.frame = CGRect(x: 0, y: 0, width: toViewController.view.frame.width, height: fromViewController.view.frame.height)
backgroundView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
backgroundView.alpha = 0
containerView.addSubview(backgroundView)
let transition = CATransition()
transition.duration = 0.5
transition.type = CATransitionType.moveIn
transition.subtype = CATransitionSubtype.fromTop
containerView.layer.add(transition, forKey: kCATransition)
For Dismiss Replace this code
containerView.addSubview(fromViewController.view!)
let transition = CATransition()
transition.duration = 0.5
transition.type = CATransitionType.fade
containerView.layer.add(transition, forKey: kCATransition)
backgroundView.frame = CGRect(x: 0, y: 0, width: testView.frame.width, height: testView.frame.height)
backgroundView.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)
self.backgroundView.alpha = 0.0

Custom UI Button not shwing title

I created a custom UI Button class in swift for a follow button, however it is not showing the button title
My code
#IBDesignable
public class GradientButton: UIButton {
override public func layoutSubviews() {
super.layoutSubviews()
layoutGradientButtonLayer()
}
// MARK: Private
private func layoutGradientButtonLayer() {
let layer = UIView()
layer.frame = CGRect(x: 191, y: 257, width: 66.6, height: 24)
let gradient = CAGradientLayer()
gradient.frame = CGRect(x: 0, y: 0, width: 66.6, height: 24)
gradient.colors = [
UIColor(red: 0.09, green: 0.85, blue: 0.88, alpha: 1).cgColor,
UIColor(red: 0, green: 0.87, blue: 0.68, alpha: 1).cgColor
]
gradient.locations = [0, 1]
gradient.startPoint = CGPoint(x: 0.78, y: 1)
gradient.endPoint = CGPoint(x: 0.15, y: 1)
self.layer.cornerRadius = 10
self.layer.addSublayer(gradient)
self.clipsToBounds = true
self.setTitle("Follow", for: UIControlState.normal)
}
}
The button appears small width and doesn't have any "Follow" text in it
Change below code you will see title:
self.layer.addSublayer(gradient)
change to
self.layer.insertSublayer(gradient, at: 0)

delete subview that use with imageView

I have a map picture in my ImageView and I want a red dot for user current location so I use this 3 lines of code for creating red dot above my ImageView
let overlay: UIView = UIView(frame: CGRect(x: xcorIn * 0.822, y: ycorIn * 1.03, width: 5, height: 5))
overlay.backgroundColor = UIColor(red: 255/255, green: 0/255, blue: 0/255, alpha: 1)
imageView.addSubview(overlay)
all I want is after of 2 seconds of red dot appear it must disappear
so I try this
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
self.imageView.delete(overlay)
})
delay function seem work but
self.imageView.delete(overlay)
return me this error
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[UIImageView delete:]:
unrecognized selector sent to instance 0x7f8bef712df0'
You need to remove overlay from the superView. You could either do this:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
overlay.removeFromSuperview()
})
Or if you donĀ“t have overlay globally, you could do this. Add a tag to your overlay and then do this:
let overlay: UIView = UIView(frame: CGRect(x: 100, y: 100, width: 5, height: 5))
overlay.tag = 0
overlay.backgroundColor = UIColor(red: 255/255, green: 0/255, blue: 0/255, alpha: 1)
imageView.addSubview(overlay)
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
for subView in self.imageView.subviews {
if subView.tag == 0 {
subView.removeFromSuperview()
}
}
})
You can remove the dot by using its reference and "removeFromSuperview()" method
let overlay: UIView = UIView(frame: CGRect(x: xcorIn * 0.822, y: ycorIn * 1.03, width: 5, height: 5))
overlay.backgroundColor = UIColor(red: 255/255, green: 0/255, blue: 0/255, alpha: 1)
imageView.addSubview(overlay)
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
overlay.removeFromSuperview()
})
You are getting that error because there is no delete method in the imageView, but there is a method called removeFromSuperview.
You are going to remove the overlay from the SuperView
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: {
overlay.removeFromSuperview()
})
Or:
self.overlay.hidden = true
Or try the following if your reference to it was a strong reference, make sure to nil that strong reference:
overlay= nil
Or animate without using dispatchQueue:
UIView.animate(withDuration: 0.5, delay: 0.3, options: [.repeat, .curveEaseOut, .autoreverse], animations: {
self.overlay.alpha = 0
}, completion: nil)

Move coordinates of UIView to LLO with Swift

I would expect this code to move my newLabel from the upper left corner (ULO) to the lower left corner (LLO) but it doesn't! Apparently I need someone to hold my hand through the process of setting (0, 0) to LLO for a UIView. I've been through the documentation and read post after post on this forum but can't seem to make it happen. Disclaimer: I am trying to accomplish this in a playground in xCode 6 beta 2 so it possible it's a bug or not supported.
var newLabel = UILabel(frame: CGRectMake(0, 0, 150, 50))
newLabel.text = "This is a test"
newLabel.layer.borderWidth = 2
newLabel.textAlignment = NSTextAlignment.Center
newLabel.backgroundColor = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.8)
var myView = UIView(frame: CGRectMake(0, 0, 200, 100))
myView.layer.borderWidth = 2
myView.addSubview(newLabel)
myView.transform = CGAffineTransformMakeScale(1, -1)
myView.backgroundColor = UIColor(red: 0.8, green: 0, blue: 0, alpha: 0.8)
It seems like you haven't added Myview in main view try this code:--
var newLabel = UILabel(frame: CGRectMake(0, 0, 150, 50))
newLabel.text = "This is a test"
newLabel.layer.borderWidth = 2
newLabel.textAlignment = NSTextAlignment.Center
newLabel.backgroundColor = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.8)
var myView = UIView(frame: CGRectMake(0, 0, 200, 100))
myView.layer.borderWidth = 2
myView.addSubview(newLabel)
myView.transform = CGAffineTransformMakeScale(1, -1)
myView.backgroundColor = UIColor(red: 0.8, green: 0, blue: 0, alpha: 0.8)
self.view.addSubview(myView);
To flip the UIView it has to be a subView of another view... My issue was I was trying to flip the mainView or baseView which apparently cant be done. This make since, since it needs a graphic space to be able to draw to. Below is the code achieving what I was looking for. Also of not I also had to "flip" my label as well to return it to it upright state (again this is logical).
var newLabel = UILabel(frame: CGRectMake(0, 0, 150, 50))
newLabel.transform = CGAffineTransformMakeScale(1, -1)
newLabel.text = "This is a test"
newLabel.layer.borderWidth = 2
newLabel.textAlignment = NSTextAlignment.Center
newLabel.backgroundColor = UIColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 0.8)
var subView = UIView(frame: CGRectMake(50, 50, 200, 100))
subView.transform = CGAffineTransformMakeScale(1, -1)
subView.layer.borderWidth = 2
subView.addSubview(newLabel)
subView.backgroundColor = UIColor(red: 0.8, green: 0, blue: 0, alpha: 0.8)
var myView = UIView()
myView = UIView(frame: CGRectMake(0, 0, 300, 200))
//myView.transform = CGAffineTransformMakeScale(1, -1)
myView.layer.borderWidth = 2
myView.addSubview(subView)
myView.backgroundColor = UIColor(red: 0, green: 0.8, blue: 0, alpha: 0.8)
Thanks #Mohit for your input in helping me to find the solution.

Resources