I'm trying to make a button rotate counterclockwise but for some strange reason it's rotating clockwise. I know the previous way to do it is by M_PI but it's been deprecated for swift 3 and replaced with CGFloat.pi. I've tried:
self.loginButton.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
but it still moves clockwise. Any idea what the syntax is to move counterclockwise?
The animation will always take the shortest way. Therefore CGFloat.pi and -CGFloat.pi animates in same position.
As we need anti-clockwise rotation we forcefully made it a shortest way by using this -(CGFloat.pi * 0.999).
UIView.animate(withDuration: 1.0, animations:{
self.loginButton.transform = CGAffineTransform(rotationAngle:-(CGFloat.pi * 0.999))
})
There is a better solution than this use CABasicAnimation for anticlockwise rotation.
let anticlockAnimation = CABasicAnimation(keyPath: "transform.rotation")
anticlockAnimation.fromValue = CGFloat.pi
anticlockAnimation.toValue = 0
anticlockAnimation.isAdditive = true
anticlockAnimation.duration = 1.0
self.loginButton.layer.add(anticlockAnimation, forKey: "rotate")
self.loginButton.transform = CGAffineTransform(rotationAngle: -CGFloat.pi)
Related
I've done a bit of research but unfortunately only found some libraries that allowed coloured circular loaders and not using an image.
So here's my issue, I've got a circular countdown which in the design I've got to implement uses a complex glow that I find really hard to reproduce as shown. The progress of this countdown is shown by this glow progressing over 3 seconds around a circle.
My initial thought was to try to modify UIView+Glow so that the glow wouldn't vary but even then I would come at a stop when it came to making my UIView radially hidden.
So I'm now thinking of simply exporting the outer glow that makes the progress bar as an image and radially hiding that (which would be faster and simpler to do in the end, rather than trying to make the exact same glow manually).
Does anyone have any idea where I should start looking or what I should be doing to hide part of a circular image using angles/rads ?
EDIT: here's what the glow looks like overlayed with the circular label (the black circle) that is used to show the countdown value.
First I would like to thank #Carpsen90 for helping me out, although his answer was not what I was looking for it helped me understand how to use CABasicAnimation and in combination with inspiration from this answer I found a solution to my problem using an image and a CAShapeLayer
for those wondering what I did here's the code I used
// countdownGlow is the glow (white and red part of my image)
func animateMask() {
let arcPath = CGMutablePath()
arcPath.move(to: CGPoint(x: self.countdownGlow.frame.width / 2, y: 0))
arcPath.addArc(center: CGPoint(x: self.countdownGlow.frame.width / 2, y: self.countdownGlow.frame.width / 2), radius: self.countdownGlow.frame.width / 2, startAngle: CGFloat(-1 * Double.pi / 2), endAngle: CGFloat(-3 * Double.pi / 2), clockwise: false)
arcPath.addArc(center: CGPoint(x: self.countdownGlow.frame.width / 2, y: self.countdownGlow.frame.width / 2), radius: self.countdownGlow.frame.width / 2, startAngle: CGFloat(-3 * Double.pi / 2), endAngle: CGFloat(-5 * Double.pi / 2), clockwise: false)
let ringLayer = CAShapeLayer(layer: self.countdownGlow.layer)
ringLayer.path = arcPath
ringLayer.strokeEnd = 0.0
ringLayer.fillColor = UIColor.clear.cgColor
ringLayer.strokeColor = UIColor.black.cgColor
ringLayer.lineWidth = self.countdownGlow.frame.width / 2
self.countdownGlow.layer.mask = ringLayer
self.countdownGlow.layer.mask?.frame = self.countdownGlow.layer.bounds
let swipe = CABasicAnimation(keyPath: "strokeEnd")
swipe.duration = 3
swipe.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
swipe.fillMode = kCAFillModeForwards
swipe.isRemovedOnCompletion = true
swipe.toValue = 1.0
ringLayer.add(swipe, forKey: "strokeEnd")
}
I couldn't seem to simply tell my arc to be a full circle so I went with half a circle once and then another half circle which worked out
If you have any improvements to offer I would gladly try it out to see, because I am sure my solution is not optimised at all
I have a UIView on my screen. I am applying layer.transform to that view with translation and rotation according to users tap movement using tap and rotation gesture. At last i want to retrieve the final x and y position with the rotation separately. Could not find any such post here to get those information from transform. Can anyone help with this?
Here is the code am using to apply the transform.
var transform = CATransform3DIdentity
transform = CATransform3DTranslate(transform, displacementX, displacementY, 1.0)
transform = CATransform3DRotate(transform, gesture.rotation, 0, 0, 1.0)
self.currentItem.imageView.layer.transform = transform
Please refer the following code,
For Applying Transform,
let degrees = 90.0
let radians = CGFloat(degrees * Double.pi / 180)
sampleView.layer.transform = CATransform3DMakeRotation(radians, 0.0, 0.0, 1.0)
To get rotation angle after transform,
let radiansFromSampleView = atan2(sampleView.transform.b, sampleView.transform.a)
let DegreesFromRadiansOFSampleView = CGFloat(180 * Double(radiansFromSampleView) / Double.pi)
For x and y positions you can directly take from frame of the view even after transformation.
Hope this can be helpful.
I have an app which animates a needle on a meter as long as the user is pressing on the screen. When the finger is lifted I need to know the rotation angle of the needle. I remove all animations as soon as the finger is lifted but I can't figure how to get the current rotation angle of the needle.
It is quite simple, this is the full solution:
Sample Setup:
imageView.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 6) // just to test (it is 30 in degrees and 0.523598775598299 in radians)
Code:
let rad: Double = atan2( Double(imageView.transform.b), Double(imageView.transform.a))
let deg: CGFloat = CGFloat(rad) * (CGFloat(180) / CGFloat.pi )
print(deg) // works, printing 30
where deg = degrees and rad = radians
Explanation:
The first line is getting the radians, and the second line is multiplying the radians by the equivalent of a radian in degrees, to get the degrees.
NOTES:
In CGAffineTransform(rotationAngle: someValue), someValue is, in fact, the radians of the angle, it is not measured in degrees. More information about:
radian
degree
PI
The value in degrees of the radian CGFloat.pi is 180, therefore you can test it for any angle depending on this.
Let me know if this helps!
I'm trying to create a very simple clock. When I apply a CGAffineTransformRotate it looks great, however on the 30th - 31st second the hand goes crazy.
An example of it going wrong.
Here is the code I'm using to animate it:
lengthInSeconds += 1
let angle = CGFloat(6.degreesToRadians * Double(lengthInSeconds))
var transform = CGAffineTransformMakeTranslation(0.0, (clockFace.frame.width/4))
secondsHand.layer.anchorPoint = CGPointMake(0.5, 1.0)
transform = CGAffineTransformRotate(transform, angle)
let spring = CASpringAnimation(keyPath: "transform.rotation")
spring.damping = 2.0//3.0
spring.duration = 0.4
spring.mass = 0.1
spring.initialVelocity = 0.0
secondsHand.layer.addAnimation(spring, forKey: "rotation")
secondsHand.transform = transform
Anyone have any idea as to why it would rotate awkwardly like this? Just to add, it happens on all passes, so at 30 seconds, 1 minute 30, 2 minutes 30 etc.
What do I have to do, if I need to rotate a UIImageView? I have a UIImage which I want to rotate by 20 degrees.
The Apple docs talk about a transformation matrix, but that sounds difficult. Are there any helpful methods or functions to achieve that?
If you want to turn right, the value must be greater than 0 if you want to rotate to the left indicates the value with the sign "-". For example -20.
CGFloat degrees = 20.0f; //the value in degrees
CGFloat radians = degrees * M_PI/180;
imageView.transform = CGAffineTransformMakeRotation(radians);
Swift 4:
let degrees: CGFloat = 20.0 //the value in degrees
let radians: CGFloat = degrees * (.pi / 180)
imageView.transform = CGAffineTransform(rotationAngle: radians)
A transformation matrix is not incredibly difficult. It's quite simple, if you use the supplied functions:
imgView.transform = CGAffineTransformMakeRotation(.34906585);
(.34906585 is 20 degrees in radians)
Swift 5:
imgView.transform = CGAffineTransform(rotationAngle: .34906585)
Swift version:
let degrees:CGFloat = 20
myImageView.transform = CGAffineTransformMakeRotation(degrees * CGFloat(M_PI/180) )
Swift 4.0
imageView.transform = CGAffineTransform(rotationAngle: CGFloat(20.0 * Double.pi / 180))
Here's an extension for Swift 3.
extension UIImageView {
func rotate(degrees:CGFloat){
self.transform = CGAffineTransform(rotationAngle: degrees * CGFloat(M_PI/180))
}
}
Usage:
myImageView.rotate(degrees: 20)
_YourImageView.transform = CGAffineTransformMakeRotation(1.57);
where 1.57 is the radian value for 90 degree
This is an easier formatting example (for 20 degrees):
CGAffineTransform(rotationAngle: ((20.0 * CGFloat(M_PI)) / 180.0))
As far as I know, using the matrix in UIAffineTransform is the only way to achieve a rotation without the help of a third-party framework.