Transform UILabel around is axis horizontally in Swift - ios

is it possible to rotate UILabel around Its axis horizontally ? Something like flip clock ?

Yes. Try this:
label.transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)

You might add a UILabel subclass, amd implement the flipping animation, like such:
#implementation FlippingLabel
- (void)flipToAlphabet:(NSString *)alphabet {
[UIView transitionWithView:self
duration:0.3
options:UIViewAnimationOptionTransitionFlipFromTop
animations: ^{
self.text = [self.text nextCharacterInSequence];
}
completion: ^(BOOL finished) {
if (![self.text isEqualToString:alphabet]) {
if (![[self.text nextCharacterInSequence] isEqualToString:#"-"]) {
[self flipToAlphabet:alphabet];
}
}
}];
}
I did something similar in one of my previous projects.
https://github.com/mehul90/Flipper

Related

animate UIImage in objective-c

I am trying to have my uiimageview move in a straight line horizontally out of bounds and loop again starting from the other side... this is the code I have in swift..
and was wondering if anyone knows how I can implement it in objective c?
let carSpeed = 20.0 / Double(view.frame.size.width)
let duration: NSTimeInterval = Double(view.frame.size.width - car.frame.origin.x) * carSpeed
UIView.animateWithDuration(duration, delay: 0.0, options: .CurveLinear, animations:
{
car.frame.origin.x = self.view.bounds.size.width
}, completion: {_ in
//reset cloud
car.frame.origin.x = -self.carImageView.frame.size.width
self.animateCars(car)
also if anyone knows any tutorials on objective C animations! thanks!
your can set the frame of image view first
UIImageView * imageView=[[UIImageView alloc]initWithFrame(x,y,width,height)];
Then set the frames in the following method
int moveValue=10 // add your desired value
[UIView animateWithDuration:0.25 animations:^{
imageView.frame=CGRectMake(x+moveValue,y,width,height);
} completion:nil];
This is your exact code converted to Objective-C:
double carSpeed = 20.0 / self.view.frame.size.width;
NSTimeInterval duration = (self.view.frame.size.width - car.frame.origin.x) * carSpeed;
[UIView animateWithDuration:duration
delay:0.0
options:UIViewAnimationOptionCurveLinear
animations:^{
car.frame = CGRectMake(self.view.bounds.size.width,
car.frame.origin.y,
car.frame.size.width,
car.frame.size.height);
}
completion:^(BOOL finished) {
if (finished) {
car.frame = CGRectMake(-self.carImageView.frame.size.width,
car.frame.origin.y,
car.frame.size.width,
car.frame.size.height);
[self animateCars:car];
}
}];

Animating a group of UIView subviews continuously

I am trying to show the movement of a vehicle on a road in my app. For this I am keeping my vehicle stationary and moving the lanes in the road from top to bottom continuously to create the effect. The lanes are added as subview to roadView and I am trying to animate all the subviews in the roadView as seen in the code below.
The problem I am facing is that the lane nearest to the bottom is moving at a faster speed compared the one at the top in the beginning although I am calculating the duration based on constant speed.
-(void)animateLanes {
for (UIView *laneView in [self.roadView subviews]) {
if (laneView.tag < 10) {
float distance = self.view.frame.size.height - CGRectGetMaxY(laneView.frame);
float duration = distance/10;
[UIView animateWithDuration:duration animations:^{
laneView.frame = CGRectMake(laneView.frame.origin.x, self.view.frame.size.height+laneView.frame.size.height, laneView.frame.size.width, laneView.frame.size.height);
} completion:^(BOOL finished) {
laneView.frame = CGRectMake(self.roadView.frame.size.width/2 - 10, -laneView.frame.size.height, 20, 40);
[self nextStep:laneView];
}];
}
}
}
-(void) nextStep:(UIView *) laneView{
float distance = self.view.frame.size.height - CGRectGetMaxY(laneView.frame);
float duration = distance/10;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionRepeat animations:^{
laneView.frame = CGRectMake(laneView.frame.origin.x, self.view.frame.size.height+laneView.frame.size.height, laneView.frame.size.width, laneView.frame.size.height);
} completion:^(BOOL finished) {
laneView.frame = CGRectMake(self.roadView.frame.size.width/2 - 10, -laneView.frame.size.height, 20, 40);
}];
}
I would most definitely look into SpriteKit for this kind of thing. The update loop in its SKScene will allow you to make sure everything is running smoothly.
However, if you do do this, you don't have to make all these UIView Animation calls. Do this:
//calculate duration and distance first, then:
[UIView animateWithDuration:duration animations:^{
for (UIView *laneView in [self.roadView subviews]) {
laneView.frame = CGRectMake(laneView.frame.origin.x, self.view.frame.size.height+laneView.frame.size.height, laneView.frame.size.width, laneView.frame.size.height);
}
} completion:^(BOOL finished) {
for (UIView *laneView in [self.roadView subviews]) {
laneView.frame = CGRectMake(self.roadView.frame.size.width/2 - 10, -laneView.frame.size.height, 20, 40);
[self nextStep:laneView];
}
}];
Although I do NOT advise doing any of this at all. Use a game library, namely SpriteKit because of its ease of integration and simplicity.
SpriteKit makes a lot more sense for this type of task, IMO. The logic would be similar and the objects would belong to SKScene instance which has a handy update method perfect for the loop effect you're aiming for.

How to stop this sequence?

i am animating a frame, through this code, which is easily understandable in code, now i am trying to stop this sequence after 20 time means in completion parentheses i need to call that function for 20 times only: how can i do that?
-(void)conveyComplete:(UIView*)v
{
[self convey:v delay:0];
}
-(void)convey:(UIView*)v delay:(int)nDelay
{
[UIView animateWithDuration:.5
delay:nDelay
options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction)
animations: ^
{
CGRect rPos = v.frame;
NSLog(#"x:%f y:%f vFrame:%f vFrame:%f" , rPos.origin.x,rPos.origin.y,v.frame.origin.x,v.frame.origin.y);
rPos.origin.x -= 5;
rPos.origin.y -=100;
v.frame = rPos;
}
completion: ^(BOOL finished)
{
[self conveyComplete:v];
NSLog(#"I:%i, F:%i",i,f);
}];
}
As your function does only animation, one possible solution is not to call function 20 times, but instead set repeat count of animation with setAnimationRepeatCount: method.
It'll looks something similar to this:
[UIView UIView animateWithDuration:.5
delay:nDelay
options:(UIViewAnimationOptionRepeat | ...)
animations: ^{
// Do your animation stuff
[UIView setAnimationRepeatCount:20];
}
completion:NULL];
But one other aspect that is worth regarding is whether you need to repeat animation 20 times at all. All you do is just stepwise shifting of you view frame. Why not to animate this at once by setting appropriate offsets and animation duration?
i have made a global integer:
int i=1;
-(void)conveyComplete:(UIView*)v{
[self convey:v delay:0];
}
-(void)convey:(UIView*)v delay:(int)nDelay{
[UIView animateWithDuration:.5
delay:nDelay
options:(UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction)
animations: ^
{
CGRect rPos = v.frame;
i+=1;// then increase +1 every time it runs
NSLog(#"x:%f y:%f vFrame:%f vFrame:%f" , rPos.origin.x,rPos.origin.y,v.frame.origin.x,v.frame.origin.y);
rPos.origin.x -= 5;
rPos.origin.y -=100;
v.frame = rPos;
}
completion: ^(BOOL finished)
{
if(i<20){
[self conveyComplete:v];
}
NSLog(#"I:%i, F:%i",i,f);
}];
}

Move & Rotate an UIImageView

I have an UIImageView with an rotation animation that loops, I need to move the UIImageView by x and y in the screen.
The rotation animation code is:
-(void)rotate{
if (leftRotate){
leftRotate = NO;
}else{
leftRotate = YES;
}
CGRect initFrame = self.frame;
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAutoreverse
animations:^{
if (leftRotate){
self.transform = CGAffineTransformRotate(self.transform, -1 * (M_PI/8));
}else{
self.transform = CGAffineTransformRotate(self.transform, M_PI / 8);
}
}
completion:^(BOOL completed) {
if (completed){
if (!stopRotate){
[self rotate];
}
}
}];
}
I try differents approaches to move the image, like setting the center but I cant move it.
I found the way, I have to set the center out side the animation:
CGPoint facePosition = CGPointMake(self.face1.center.x+1,
self.face1.center.y);
self.face1.center = facePosition;

How to add animation while changing the hidden mode of a uiview?

I want to add animation to a view while changing its hidden mode i.e
my_view.hidden=YES;
I have added a button in navigationbar. When we click on it the new view is set to be unhide. It draws at the upper of the navigation table.
Animate the view's opacity from 100% to 0%. Have the animation completion callback set the view to be hidden. You might also want to reset the opacity back to 100% during the callback, so the view will display fully opaque when you unhide it.
yourView.alpha = 0.0 //for zero opacity
yourView.alpha = 1.0 //for 100% opacity
There is no animation for hiding however; you get the same result with the Swift code below:
UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: {
self.yourView.alpha = 0 // Here you can change the alpha property of the view
}, completion: { _ in
self.yourView.isHidden = true // Here you hide it when animation done
})
Unfortunately, hidden is not a property that is animatable through UIView animations. I think your best bet may be to use one of the animations #Erik B suggested, or start dabbling with Core Animations which are much more powerful. Take a glance at the documentation for UIView animations and Core Animations.
I achieved something like what your suggesting by using UIView animations to slide the new view from below another view. This made it appear like a drawer sliding out. If you want to do something like that, you need to intercept the touch up inside event and place the animation code there.
- (IBAction)buttonClicked:(id)sender {
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseOut
animations:^(void) {
self.myView.frame = /* set the frame here */
}
completion:NULL];
}
I think more appropriate way to do it is:
[UIView transitionWithView:aView
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^(void){
aView.hidden = NO;
}
completion:nil];
Updated to Swift 3:
UIView.animate(withDuration: 0.2, delay: 0.2, options: .curveEaseOut,
animations: {firstView.alpha = 0},
completion: { _ in firstView.isHidden = true
//Do anything else that depends on this animation ending
})
And if you wish to animate something back after first view is gone, you can replicate the code inside the completion block with alpha = 1 and hidden = false.
Here's a category I wrote to introduce a new "hidden" property on UIView which correctly supports animation:
#implementation UIView (AnimateHidden)
-(void)setHiddenAnimated:(BOOL)hide
{
[UIView animateWithDuration:0.5
delay:0.0
options: UIViewAnimationCurveEaseOut
animations:^
{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
if (hide)
self.alpha=0;
else
{
self.hidden= NO;
self.alpha=1;
}
}
completion:^(BOOL b)
{
if (hide)
self.hidden= YES;
}
];
}
#end
This is corrected N.J. version:
#implementation UIView (AnimateHidden)
-(void)setHiddenAnimated:(BOOL)hide duration:(NSTimeInterval)duration {
if(self.hidden == hide)
return;
if(hide)
self.alpha = 1;
else {
self.alpha = 0;
self.hidden = NO;
}
[UIView animateWithDuration:duration animations:^{
if (hide)
self.alpha = 0;
else
self.alpha = 1;
} completion:^(BOOL finished) {
if(finished)
self.hidden = hide;
}];
}
#end
Here is swift version for this :
Swift 2
UIView.animateWithDuration(0.5, delay: 0.2, options: UIViewAnimationOptions.CurveEaseOut, animations: {
objView.alpha = 0
}, completion: { finished in
objView.hidden = true
})
Swift 3, 4, 5
UIView.animate(withDuration: 0.5, delay: 0.2, options: UIView.AnimationOptions.curveEaseOut, animations: {
objView.alpha = 0
}, completion: { finished in
objView.isHidden = true
})
This performs animation with duration of 5 seconds and after delay of 2 seconds.
Available AnimationOptions are :
CurveEaseInOut, CurveEaseIn, CurveEaseOut, CurveLinear
Since a few of these answers are a bit cluttered I figured I could post my minimalistic design of this API. I also added the delay and duration - because why not.
In the implementation we have.
#import "UIView+AnimateHidden.h"
#implementation UIView (AnimateHidden)
- (void)setHiddenAnimated:(BOOL)hide
delay:(NSTimeInterval)delay
duration:(NSTimeInterval)duration {
[UIView animateWithDuration:duration
delay:delay
options:UIViewAnimationOptionAllowAnimatedContent
animations:^{
if (hide) {
self.alpha = 0;
} else {
self.alpha = 0;
self.hidden = NO; // We need this to see the animation 0 -> 1
self.alpha = 1;
}
} completion:^(BOOL finished) {
self.hidden = hide;
}];
}
#end
In the header file we have.
#import <UIKit/UIKit.h>
#interface UIView (AnimateHidden)
- (void)setHiddenAnimated:(BOOL)hide
delay:(NSTimeInterval)delay
duration:(NSTimeInterval)duration;
#end
NJ's and Stanislav's answers here helped me make a new category for this, which I think improves on their answers, so thought I'd post what I came up with in case it helps anyone else.
Note it will only work in iOS4 or later as it's using blocks.
UIView+AnimateHidden.m
#import "UIView+AnimateHidden.h"
#implementation UIView (AnimateHidden)
- (void)setHidden:(BOOL)hidden animated:(BOOL)animated
{
// If the hidden value is already set, do nothing
if (hidden == self.hidden) {
return;
}
// If no animation requested, do the normal setHidden method
else if (animated == NO) {
[self setHidden:hidden];
return;
}
else {
// Store the view's current alpha value
CGFloat origAlpha = self.alpha;
// If we're unhiding the view, make it invisible initially
if (hidden == NO) {
self.alpha = 0;
}
// Unhide the view so we can see the animation
self.hidden = NO;
// Do the animation
[UIView animateWithDuration:0.5
delay:0.0
options: UIViewAnimationOptionCurveEaseOut
animations:^{
// Start animation block
if (hidden == YES) {
self.alpha = 0;
}
else {
self.alpha = origAlpha;
}
// End animation block
}
completion:^(BOOL b){
// Start completion block
// Finish up by hiding the view if necessary...
self.hidden = hidden;
// ... and putting back the correct alpha value
self.alpha = origAlpha;
// End completion block
}];
}
}
#end
Another version if you wish to use more complex animation types or animations not supported by the UIView
- (void)setHidden:(BOOL)hidden withAnimationDuration:(NSTimeInterval)duration
{
CATransition* transition = ({
CATransition* its = [CATransition animation];
its.duration = duration;
its.timingFunction =
[CAMediaTimingFunction
functionWithName: kCAMediaTimingFunctionEaseInEaseOut];
its.type = kCATransitionPush;
its.subtype = (hidden ? #"fromBottom" : #"fromTop");
its
});
UIView* containerView = self.superview;
[containerView.layer removeAllAnimations];
[containerView.layer addAnimation: transition forKey: kCATransition];
self.hidden = hidden;
if (!hidden) {
[self.superview bringSubviewToFront: self];
}
}
Here is the code I used to model a view "growing" and "shrinking" on a "show more..." and "show less ..." button click. Modeled off the answer from Palyancodr
This approach allows me to create both views in the storyboard so that the constraints work as expected on the different iOS devices and I don't need to custom code all the constraints.
#IBAction func showMoreOrLessAction(_ sender: Any) {
// if small view showing
if showMoreLargeView.isHidden {
showMoreSmallView.isHidden = true
//showMoreLargeView.isHidden = false
UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: {
self.showMoreLargeView.alpha = 1 // Here you will get the animation you want
}, completion: { _ in
self.showMoreLargeView.isHidden = false // Here you hide it when animation done
})
}
else { // large view showing
//showMoreSmallView.isHidden = false
UIView.animate(withDuration: 0.2, delay: 0, options: [], animations: {
self.showMoreSmallView.alpha = 1 // Here you will get the animation you want
}, completion: { _ in
self.showMoreSmallView.isHidden = false // Here you hide it when animation done
})
showMoreLargeView.isHidden = true
}
}

Resources