View don't appear the second time [Swift] - swift

In my swift app I've create these two functions:
func presentAlertView() {
backgroundLogOutView.frame = UIScreen.main.bounds
backgroundLogOutView.backgroundColor = currentTheme.backgroundColor.withAlphaComponent(0.5)
logOutAlertView.frame.size = CGSize(width: 200, height: 200)
logOutAlertView.center = CGPoint(x: view.frame.width / 2, y: view.frame.height / 2 - (navigationController?.navigationBar.frame.size.height)!)
view.addSubview(backgroundLogOutView)
backgroundLogOutView.addSubview(logOutAlertView)
logOutAlertView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
logOutAlertView.alpha = 0
UIView.animate(withDuration: 0.4, animations: {
self.logOutAlertView.alpha = 1
self.logOutAlertView.transform = CGAffineTransform.identity
})
}
#objc func removeAlertView() {
UIView.animate(withDuration: 0.4, animations: {
self.logOutAlertView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.logOutAlertView.alpha = 0
self.backgroundLogOutView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)
self.backgroundLogOutView.alpha = 0
}) {(success: Bool) in
self.logOutAlertView.removeFromSuperview()
self.backgroundLogOutView.removeFromSuperview()
self.tableView.deselectRow(at: [0,4], animated: true)
}
}
By tapping a button the function presentAlertView() is invoked and the views appear then when the function removeAlertView() is invoked the views disapeear. And here all ok.
But when I tapped the button the second time the views don't appear!
Why this happened?
Thank you

self.backgroundLogOutView.alpha = 0
is present in removeAlertView().
self.backgroundLogOutView.alpha = 1
may be missing in presentAlertView().

Related

CGAffineTransform(translationX: , y: ) will only move UIImage View to the right

I have two UIButtons for moving UImages left and right accordingly. The code for the both UIButtons is as follows,
#IBAction func MoveLeft(_ sender: Any) {
let yPosition1 = myslider.frame.origin.y
let yPosition2 = ImageView.frame.origin.y
let yPosition3 = ImageView2.frame.origin.y
UIView.animate(withDuration: 0.0, delay: 0.0, options: [], animations: {
self.myslider.transform = CGAffineTransform(translationX: -0.1, y: yPosition1)
self.ImageView.transform = CGAffineTransform(translationX: -0.1, y: yPosition2)
self.ImageView2.transform = CGAffineTransform(translationX: -0.1, y: yPosition3)
}, completion: nil)
}
#IBAction func MoveRight(_ sender: Any) {
let yPosition1 = myslider.frame.origin.y
let yPosition2 = ImageView.frame.origin.y
let yPosition3 = ImageView2.frame.origin.y
UIView.animate(withDuration: 0.0, delay: 0.0, options: [], animations: {
self.myslider.transform = CGAffineTransform(translationX: 0.1, y: yPosition1)
self.ImageView.transform = CGAffineTransform(translationX: 0.1, y: yPosition2)
self.ImageView2.transform = CGAffineTransform(translationX: 0.1, y: yPosition3)
}, completion: nil)
}
the values for the translation are opposite of each other so in theory the buttons should move the UIImages in different directions correct? Although when I run the and try using the "MoveLeft" UIButton the UIImages move in the same direction as if I was using the "MoveRight" UIButton. Any ideas on how to fix this issue would be greatly appreciated

I'm trying to make a card that slides while on swipe in swift

I'm having a hard time with animations and PanGestureRecognizers, I want a view that slides by dragging up or dawn with your finger. It has 4 parts
1 - 2 the height, width and bottom constraints need to be changed
2 - 3 the height is the maximum height and you can slide it in or out
3 - 4 the card is at its maximum height and you can swipe it down
here is an image for a better understanding
thanks!
this is how I would do it.
var theView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
// First create your view.
theView = UIView(frame: CGRect(x: 40, y: self.view.bounds.height - 120, width: self.view.frame.width - 80, height: 100))
// set its background color
theView.backgroundColor = UIColor.black
// Create the round corners
theView.layer.cornerRadius = 20
// And add it to the view
self.view.addSubview(theView)
// Create the UIPanGestureRecognizer and assign the function to the selector
let gS = UIPanGestureRecognizer(target: self, action: #selector(growShink(_:)))
// Enable user interactions on the view
theView.isUserInteractionEnabled = true
// Add the gesture recognizer to the view
theView.addGestureRecognizer(gS)
}
// The control value is used to determine wether the user swiped up or down
var controlValue:CGFloat = 0
var animating = false
// The function called when the user swipes
#objc func growShink(_ sender:UIPanGestureRecognizer){
let translation = sender.location(in: theView)
// Check the control value to see if it has been set
if controlValue != 0 && !animating{
// if it has been set check that the control value is greater than the new value recieved by the pan gesture
if translation.x < controlValue{
animating = true
// If it is, change the values of the frame using animate
UIView.animate(withDuration: 0.5, animations: {
self.theView.frame = CGRect(x: 0, y: self.view.bounds.height - 300, width: self.view.frame.width, height: 300)
}, completion: {finished in
UIView.animate(withDuration: 1.0, animations: {
self.theView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
}, completion: {finished in self.animating = false; self.controlValue = 0})})
}else if translation.x > controlValue{
animating = true
// else, change the values of the frame back.
UIView.animate(withDuration: 0.5, animations: {
self.theView.frame = CGRect(x: 0, y: self.view.bounds.height - 300, width: self.view.frame.width, height: 300)
}, completion: {finished in
UIView.animate(withDuration: 1.0, animations: {
self.theView.frame = CGRect(x: 40, y: self.view.bounds.height - 120, width: self.view.frame.width - 80, height: 100)
}, completion: {finished in self.animating = false; self.controlValue = 0})})
}
}
// set the control value to the value received from the pan gesture
controlValue = translation.x
}
}
You can adjust the width and height values however you want.

Toast UILabel appears off screen, despite me setting y correctly

I have a Toast extension on a ViewController that inherits class ViewControllerList: UITableViewController, UIPopoverPresentationControllerDelegate { and everything is fine except that when I do this
extension UIViewController {
func showToast(message : String) {
let height = UIScreen.main.bounds.height
let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: height-100, width: 150, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
self.view.addSubview(toastLabel)
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
}
}
the toast ALWAYS appears off screen .. in a long uitableview .. no matter how I set the y it always thinks in terms of document.. I have debugged it and y=676 yet it appears about placement at around ~900 ...100 off the bottom of the tableView just inside the last cell
why is this and how do I fix it?
Please do not mark this down - TRY to give an answer
Instead of adding to self.view, add your toast label as a subview of the window:
extension UIViewController {
func showToast(message : String) {
let window = (UIApplication.shared.delegate as! AppDelegate).window
let height = window.bounds.height
let toastLabel = UILabel(frame: CGRect(x: window.bounds.width/2 - 75, y: height-100, width: 150, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
// notice the change here
window.addSubview(toastLabel)
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
}
}
This avoids the problems you have to deal with when the super view is a scroll view.
Add a new function addToTopView(view : UIView) and use like here.
extension UIViewController {
/// adding views as a subview of the top view = window
func addToTopView(view : UIView) {
if let d = UIApplication.shared.delegate, let window = d.window! {
window.addSubview(view)
// handle constraints or anythings
}
}
func showToast(message : String) {
let height = UIScreen.main.bounds.height
let toastLabel = UILabel(frame: CGRect(x: self.view.frame.size.width/2 - 75, y: height-100, width: 150, height: 35))
toastLabel.backgroundColor = UIColor.black.withAlphaComponent(0.6)
toastLabel.textColor = UIColor.white
toastLabel.textAlignment = .center;
toastLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
toastLabel.text = message
toastLabel.alpha = 1.0
toastLabel.layer.cornerRadius = 10;
toastLabel.clipsToBounds = true
addToTopView(view: toastLabel) // here is update
UIView.animate(withDuration: 4.0, delay: 0.1, options: .curveEaseOut, animations: {
toastLabel.alpha = 0.0
}, completion: {(isCompleted) in
toastLabel.removeFromSuperview()
})
}
}

Swift animation chaining using CGAffineTransforms

I'm trying to create a background animation for my app. What I'm trying to achieve for part of it is:
1) An image (random colour / shape chosen from an array) appears randomly on the view. 2) It then grows in size rapidly (from not visible, to visible). 3) Then will slowly move in a given direction, while rotating, for 10ish seconds. 4) Then it will scale back down to a non-visible size and be removed from the view.
What I'm finding is that the shape will appear correctly in steps 1 and 2. Then, the shape will jump to a random position on the screen at the start of animation/step 3 (transition3 in the below code). While it moves, it also decreases in size. Then for step 4 it jumps back to it's original position in step 1 & 2, before shrinking off the screen as intended.
I cannot for the life of me work out what's going on here. I'm hoping I haven't missed something embarrassingly obvious.
Thanks in advance for any help!
class BackgroundAnimation {
func animation(animationView: UIView) {
let colourArray = [
UIColor(red:0.99, green:0.80, blue:0.05, alpha:1.0),
UIColor(red:0.06, green:0.22, blue:0.29, alpha:1.0),
UIColor(red:0.95, green:0.18, blue:0.30, alpha:1.0),
UIColor(red:0.35, green:0.77, blue:0.92, alpha:1.0),
UIColor(red:0.95, green:0.61, blue:0.19, alpha:1.0)
]
let imageArray = [
"Cross",
"Circle",
"Halfmoon",
"Square",
"Triangle"
]
//Animation constants
let initialDimensions = 10
let pathLength: CGFloat = 100
let pathDuration = 10
let scaleFactor: CGFloat = 5
let scaleDuration = 1
//Select the random image and random colour that is to be animated.
let image = UIImage(named: imageArray[Int.random(in: 0...imageArray.count - 1)])
let imageView = UIImageView(image: image)
imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = colourArray[Int.random(in: 0...colourArray.count - 1)]
imageView.contentMode = .scaleAspectFit
imageView.frame = CGRect(x: 0, y: 0, width: initialDimensions, height: initialDimensions)
animationView.insertSubview(imageView, at: 0)
//create a random start location and angle of direction
let startPointX = CGFloat.random(in: 0...animationView.frame.width)
let startPointY = CGFloat.random(in: 0...animationView.frame.height)
let pathAngle = CGFloat.random(in: 0...(CGFloat.pi * 2))
imageView.center = CGPoint(x: startPointX, y: startPointY)
//Calculate the endpoint from path angle and length
let translationX = pathLength * sin(pathAngle)
let tanslationY = -(pathLength * cos(pathAngle))
//Define the transitions for the aniamtion
var transition1 = CGAffineTransform.identity
transition1 = transition1.scaledBy(x: scaleFactor, y: scaleFactor)
var transition2 = CGAffineTransform.identity
transition2 = transition2.translatedBy(x: translationX, y: tanslationY)
transition2 = transition2.rotated(by: CGFloat.random(in: CGFloat.pi * 1/4 ... CGFloat.pi * 3/4))
var transition3 = CGAffineTransform.identity
transition3 = transition3.scaledBy(x: 0.001, y: 0.001)
UIView.animate(withDuration: TimeInterval(scaleDuration), delay: 0, options: .beginFromCurrentState, animations: {
imageView.transform = transition1
}, completion: {finished in
UIView.animate(withDuration: TimeInterval(pathDuration), delay: 0, options: .beginFromCurrentState, animations: {
imageView.transform = transition2
}, completion: { finished in
UIView.animate(withDuration: TimeInterval(scaleDuration), delay: 0, options: .beginFromCurrentState, animations: {
imageView.transform = transition3
}, completion: { finished in
imageView.removeFromSuperview()
})
})
})
}
}
change your position with imageView.center OR imageView.frame.origin
imageView.frame.origin = CGPoint(x: translationX, y: tanslationY)
but you should calculate the destination, then set frame.origin to the destination
In ref to Ehsan's helpful response:
This has fixed the movement issue, but the imageView is getting smaller when I try to apply the rotation in the second animation block. Updated code below:
class BackgroundAnimation {
func animation(animationView: UIView) {
let colourArray = [
UIColor(red:0.99, green:0.80, blue:0.05, alpha:1.0),
UIColor(red:0.06, green:0.22, blue:0.29, alpha:1.0),
UIColor(red:0.95, green:0.18, blue:0.30, alpha:1.0),
UIColor(red:0.35, green:0.77, blue:0.92, alpha:1.0),
UIColor(red:0.95, green:0.61, blue:0.19, alpha:1.0)
]
let imageArray = [
"Cross",
"Circle",
"Halfmoon",
"Square",
"Triangle"
]
//Animation constants
let initialDimensions = 10
let pathLength: CGFloat = 100
let pathDuration = 10
let scaleFactor: CGFloat = 3
let scaleDuration = 1
//Select the random image and random colour that is to be animated.
let image = UIImage(named: imageArray[Int.random(in: 0...imageArray.count - 1)])
let imageView = UIImageView(image: image)
imageView.image = imageView.image?.withRenderingMode(.alwaysTemplate)
imageView.tintColor = colourArray[Int.random(in: 0...colourArray.count - 1)]
imageView.contentMode = .scaleAspectFit
imageView.frame = CGRect(x: 0, y: 0, width: initialDimensions, height: initialDimensions)
animationView.insertSubview(imageView, at: 0)
//create a random start location and angle of direction
let startPointX = CGFloat.random(in: 0...animationView.frame.width * 0.9)
let startPointY = CGFloat.random(in: 0...animationView.frame.height * 0.9)
let pathAngle = CGFloat.random(in: 0...(CGFloat.pi * 2))
imageView.center = CGPoint(x: startPointX, y: startPointY)
//Calculate the endpoint from path angle and length
let translationX = pathLength * sin(pathAngle)
let translationY = (pathLength * cos(pathAngle))
let endPointX = startPointX + translationX
let endPointY = startPointY + translationY
//Define the transitions for the aniamtion
var transition1 = CGAffineTransform.identity
transition1 = transition1.scaledBy(x: scaleFactor, y: scaleFactor)
var transition2 = CGAffineTransform.identity
transition2 = transition2.rotated(by: CGFloat.random(in: CGFloat.pi * 1/4 ... CGFloat.pi * 3/4))
var transition3 = CGAffineTransform.identity
transition3 = transition3.scaledBy(x: 0.001, y: 0.001)
UIView.animate(withDuration: TimeInterval(scaleDuration), delay: 0, options: .beginFromCurrentState, animations: {
imageView.transform = transition1
}, completion: {finished in
UIView.animate(withDuration: TimeInterval(pathDuration), delay: 0.5, options: [.beginFromCurrentState, .curveLinear], animations: {
imageView.frame.origin = CGPoint(x: endPointX, y: endPointY)
imageView.transform = transition2
}, completion: { finished in
UIView.animate(withDuration: TimeInterval(scaleDuration), delay: 0.5, options: .beginFromCurrentState, animations: {
imageView.transform = transition3
}, completion: { finished in
imageView.removeFromSuperview()
})
})
})
}
}

UIView with custom shaped frame: Animation not behaving as expected

I want to animate a drawer with a custom shape, however the expected popOut() animation appear incorrect.
What part did I missed to make it transition without a blink ?
Why is popIn() displaying ok but not popOut() ?
Edit:
I tried animating the layer with
//pop
self.layer.transform = CATransform3DMakeScale(1, 0, 1)
and
//unPop
let transform = CATransform3DConcat(
CATransform3DMakeScale(1, 0, 1),
CATransform3DMakeTranslation(0, 0 - self.frame.height / 2, 0))
self.layer.transform = transform
It looks great,but I would like the top of my frame to be fixed, and only animate it by making it grow from the bottom...
Initial Result:
Initial Code:
// Points reference
// 1-------5
// | |
// | |
// | |
// | |
// | |
// | |
// | |
// 2\ /4
// \ /
// \ /
// 3
class PowerUpDrawer : UIView {
var triangleHeight : CGFloat
var orignalHeight : CGFloat = 0
var orignalY : CGFloat = 0
var isPoped : Bool = true {
didSet {
if (isPoped) {
pop()
} else {
unPop()
}
}
}
//XXX
override init(frame: CGRect) {
triangleHeight = 25
super.init(frame: frame)
}
//XXX
required init(coder aDecoder: NSCoder) {
triangleHeight = 25
super.init(coder: aDecoder)
orignalHeight = frame.height
orignalY = frame.origin.y
}
override var frame: CGRect {
didSet {
let bezierpath = UIBezierPath()
bezierpath.moveToPoint(CGPoint(x: 0, y: 0)) // 1
bezierpath.addLineToPoint(CGPoint(x: 0, y: frame.height - triangleHeight)) // 2
bezierpath.addLineToPoint(CGPoint(x: frame.width / 2, y: frame.height))// 3
bezierpath.addLineToPoint(CGPoint(x: frame.width, y: frame.height - triangleHeight))// 4
bezierpath.addLineToPoint(CGPoint(x: frame.width, y: 0))// 5
let mask = CAShapeLayer()
mask.frame = bounds
mask.path = bezierpath.CGPath
self.layer.mask = mask
}
}
#IBAction func toggle() {
isPoped = !isPoped
}
func pop() {
UIView.animateWithDuration(1, delay: 0.5, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: nil, animations: { () -> Void in
self.frame = CGRectMake(self.frame.origin.x, self.orignalY, self.frame.width, self.orignalHeight)
}) { (Bool) -> Void in
};
}
func unPop() {
UIView.animateWithDuration(1, delay: 0.5, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: nil, animations: { () -> Void in
self.frame = CGRectMake(self.frame.origin.x, self.orignalY, self.frame.width, self.triangleHeight)
}) { (Bool) -> Void in
};
}
}
This was an interesting problem. Can you try this as your unPop() function. I am offsetting enough height to make it feel like the top end is staying still. You can try any scaleFactor.
func unPop() {
UIView.animateWithDuration(1, delay: 0.5, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.8, options: nil, animations: { () -> Void in
let scaleFactor:CGFloat = 0.25
let offset = -(self.frame.height * (1 - scaleFactor))/2
let transform = CATransform3DConcat(
CATransform3DMakeScale(1, scaleFactor, 1),
CATransform3DMakeTranslation(0, offset, 0))
self.layer.transform = transform
}) { (Bool) -> Void in
};
}