I have a button (openMenu) that I am animating down (works fine) and rotate (works the first time) with a "drawer". The first time it rotates it works.. but when I try to rotate again it wigs out and hides the image and shows the button title? Any ideas of why? I need it to just rotate back another 45 degrees. Don't know why it would do this.
Also - see GIF image below so you see what is happening.
- (void)viewDidLoad
{
[super viewDidLoad];
draw1 = 0;
scrollView.frame = CGRectMake(0, -200, 768, 200);
[scrollView setContentSize:CGSizeMake(768, 200)];
openMenu.frame = CGRectMake(680, 100, 55, 55);
}
- (IBAction)openMenu:(id)sender {
if (draw1 == 0) {
draw1 = 1;
CGRect optionsDrawer = scrollView.frame;
CGRect optionsButton = openMenu.frame;
optionsDrawer.origin.y += 200;
optionsButton.origin.y += 200;
[UIView animateWithDuration:0.5
animations:^{
scrollView.frame = optionsDrawer;
openMenu.frame = optionsButton;
openMenu.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(45));
}];
} else {
draw1 = 0;
CGRect optionsDrawer = scrollView.frame;
CGRect optionsButton = openMenu.frame;
optionsDrawer.origin.y -= 200;
optionsButton.origin.y -= 200;
[UIView animateWithDuration:0.5
animations:^{
scrollView.frame = optionsDrawer;
openMenu.frame = optionsButton;
openMenu.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(45));
}];
}
}
Do like this, i am using layers to animate, it is easy, once u rotate, dont need to rotate again, just brings back to original state. I did like this it works for me, just try this.
since i am using layers add "QuartzCore" library and import this
#import<QuartzCore/QuartzCore.h> //include this
if (draw1 == 0)
{
....//your code
[UIView animateWithDuration:0.1 animations:^{
detailButton.layer.transform = CATransform3DMakeRotation((180) * 45, 0, 0, 1);
}];
}
else
{
....//your code
[UIView animateWithDuration:0.1 animations:^{
detailButton.transform = CGAffineTransformIdentity; //brings back to original position by animating
}];
}
hope this helps u :)
If you want to rotate the button back - you need to provide negative number as the value for CGAffineTransformMakeRotation().
Here is the snippet from Apple Docs:
CGAffineTransformMakeRotation()
Returns an affine transformation matrix constructed from a rotation
value you provide.
CGAffineTransform CGAffineTransformMakeRotation ( CGFloat angle );
The angle, in radians, by which this matrix rotates
the coordinate system axes. In iOS, a positive value specifies
counterclockwise rotation and a negative value specifies clockwise
rotation. In OS X, a positive value specifies clockwise rotation and a
negative value specifies counterclockwise rotation.
Hope this helps!
Related
I've got a button. After you click it, it disappears. I want to make it move a UIImageView continuously down a page with one click.
I've tried a for loop statement but the Image just drops down 200 y coordinates. This is the statement:
for (int i = 1; i <= 200; i++)
{
CGRect oldFrame = _rocketship.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y + 1, oldFrame.size.width, oldFrame.size.height);
_rocketship.frame = newFrame;
}
[self.rocketship startAnimating];
I would think that the Image would continuously go down the page, hence the for statement, but it doesn't. Is there any other way to do this?
(PS: The while loop statement does the same thing)
In IOS the screen is updated when the main thread is available and not currently running anything.
What you are doing is not going to work ever. All you are doing is setting the views position to off the screen because the for loop will finish before the vote is updated.
What you need to do is use core animation.
There is a class method on UIView that starts with "aninateWithDuration". There are several different methods.
These are the methods that you need to use in order to animate anything in IOS.
I can't answer with code at the moment as I'm on a mobile but check the docs for UIView. It will have documentation for these animation methods.
The method is...
[UIView animateWithDuration:1.0
animations:^{
// set the end position here
}];
Also I have a feeling that you will probably have auto layout on. If so let me know because there are different ways of animating if that is the case.
Try something like this instead:
[UIView animateWithDuration:1.0 animations:^{
CGRect oldFrame = _rocketship.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y + 200, oldFrame.size.width, oldFrame.size.height);
_rocketship.frame = newFrame;
}];
Josue Espinosa is almost correct
[UIView animationWithDuration:1.0{
CGRect oldFrame = _rocketship.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y + 1, oldFrame.size.width, oldFrame.size.height);
_rocketship.frame = newFrame;
but you probably want to move the image more then 1 pixel. the way this work is that this will animate the movement to the new location from point A to point B taking the time duration. in the code above it will take 1 second to move the button from point A to point B so say you want to move the button down 200 pixel the coude should be:
[UIView animationWithDuration:1.0
animations:^{
CGRect oldFrame = _rocketship.frame;
CGRect newFrame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y + 200, oldFrame.size.width, oldFrame.size.height);
_rocketship.frame = newFrame;
}];
this will basically animate any visual change you set as being the end result. from state A to state B.
I'm probably missing something simple, but trying to do a simple "Ken Burns Effect" with an image view.
First the code:
[UIView animateWithDuration:20
delay:2
options:UIViewAnimationCurveLinear
animations:^{
CGAffineTransform move = CGAffineTransformMakeTranslation(40, 40);
CGAffineTransform zoom = CGAffineTransformMakeScale(1.2, 1.2);
CGAffineTransform transform = CGAffineTransformConcat(zoom, move);
self.imageView.transform = transform;
}
completion:^(BOOL finished){
NSLog(#"Done");
}];
I expected this to start with the image view at normal scale and expand it to 120% of the size over 20 seconds. What actually happens is that it starts out immediately smaller than normal size, then expands to normal size.
If I use the reciprocal of the scale value, it starts out zoomed in and then zooms out to normal scale which is the opposite of the effect I want.
Any ideas?
Ok, this actually worked and does what I want.
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
transformAnimation.duration = 20.0;
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
transformAnimation.removedOnCompletion = NO;
transformAnimation.fillMode = kCAFillModeForwards;
CATransform3D xform = CATransform3DIdentity;
xform = CATransform3DScale(xform, 1.2, 1.2, 1.0);
xform = CATransform3DTranslate(xform, 60, -60, 0);
transformAnimation.toValue = [NSValue valueWithCATransform3D:xform];
[self.imageView.layer addAnimation:transformAnimation forKey:#"transformAnimation"];
It sounds like the view is being re-laid out by its parent view in response to the change in transform, casing it to be scaled down to the end result of the transform as soon as the transform is set in the animation block. The key is that your first attempt makes changes directly to the view, while the second approach works with the layer.
Have you try starting form the current transform of your imageView ?
[UIView animateWithDuration:20
delay:2
options:UIViewAnimationCurveLinear
animations:^{
CGAffineTransform trans = self.imageView.transform;
CGAffineTransformTranslate(trans, 40, 40);
CGAffineTransformScale(trans, 1.2, 1.2);
self.imageView.transform = trans;
}
completion:^(BOOL finished){
NSLog(#"Done");
}];
In my app I have a scrollview and when I press a button it is hidden when I press again it shows up.
I use scrollview.hidden = YES (or NO) to do it.
But I want to do it with an animation. For example, it may disappear from the bottom of the screen by moving and shows up with the same way. How can I do that?
edit:
[UIView beginAnimations:#"myAnimation" context:nil];
CGRect Frame = bottomScroller.frame;
if(Frame.origin.y == 380){
Frame.origin.y = 460;
}else{
Frame.origin.y = 380;
}
bottomScroller.frame = Frame;
[UIView commitAnimations];
This solved my problem...
You may check UIView animations. It's pretty easy. For example to animate translation you may use something like:
[UIView beginAnimations:#"myAnimation" context:nil];
CGRect Frame = yourView.frame;
Frame.origin.y = 0;
yourView.frame = Frame;
[UIView commitAnimations];
Then to move it back:
[UIView beginAnimations:#"myAnimation" context:nil];
CGRect Frame = yourView.frame;
Frame.origin.y = 100;
yourView.frame = Frame;
[UIView commitAnimations];
Changes in frame, alpha and some other parameters will be automatically animated.
You can use animations like so:-
[UIView animateWithDuration:2.0 animations:^{
[scrollview setframe:CGRectMake(xpos, ypos, width, height)];
}];
If you want to slide the scrollview on or off the screen set its y position - the bottom of the view is you want to hide it, the normal y position if you want to show it.
The 2.0 is an animation length, this can be changed to whatever you need it to be!
You can do this by using simple view animations. Here's an example of how you might do this:
// myScrollView is your scroll view
-(void)toggleShow{
CGFloat targetAlpha = myScrollView.alpha == 1 ? 0 : 1;
CGFloat yPosition = targetAlpha == 1 ? 0 : self.view.frame.size.height;
[UIView animateWithDuration:1.0 animations:^{
myScrollView.frame = CGRectMake(myScrollView.frame.origin.x, yPosition, myScrollView.frame.size.width, myScrollView.frame.size.height);
myScrollView.alpha = targetAlpha;
}];
}
targetAlpha will always be the opposite of the current state (1 or 0), and if it's 0 then the y position will be set to the bottom of the parent view. Using the new-school UIView animations API with blocks we can execute these changes to the scroll view over 1 second (in my example).
ScrollView appers from down side of screen with animation. I think this up-animation is what you want.
// ScrollView appearing animation
- (void)ScrollViewUpAnimation
{
// put the scroll view out of screen
CGRect frame = ScrollView.frame;
[self.view addSubview:ScrollView];
ScrollView.frame = CGRectMake(0, 460, frame.size.width, frame.size.height);
// setting for animation
CGPoint fromPt = ScrollView.layer.position;
CGPoint toPt = CGPointMake(fromPt.x, fromPt.y - frame.size.height - 44);
CABasicAnimation* anime =
[CABasicAnimation animationWithKeyPath:#"position"];
anime.duration = 0.2;
anime.fromValue = [NSValue valueWithCGPoint:fromPt];
anime.toValue = [NSValue valueWithCGPoint:toPt];
// change the position of Scroll View when animation start
[ScrollView.layer addAnimation:anime forKey:#"animatePosition"];
ScrollView.layer.position = toPt;
}
The following code is a method I created inside a UIViewController to popup/down a "reader" overlay on top of the controller's own view. The intention is for the reader to begin as transparent, size zero, at a specific point. "Popup" is then animated as increasing in opacity and size, and shifts towards an application frame central position. "Popdown" is subsequently animated as the reverse, shrinking back whilst moving toward a specified location, fading out.
The popup code works exactly as desired. However, the popdown version (i.e. code executed if isPopup == NO) immediately changes the bounds rather than doing so gradually. Thus the popdown animation shows from the beginning a 1 pixel square view moving towards its destination and fading out.
-(void)popupReader:(BOOL)isPopup from:(CGPoint)loc {
CGFloat newAlpha = 0.0f;
CGPoint newCenter = CGPointZero;
CGRect newBounds = CGRectZero;
CGRect appFrame = [UIScreen mainScreen].applicationFrame;
CGSize readerSize = [self viewSize];
if (isPopup) {
newAlpha = 1.0f;
newCenter = CGPointMake(appFrame.origin.x+appFrame.size.width/2,
appFrame.origin.y+appFrame.size.height/2);
newBounds = CGRectMake(0,0,readerSize.width,readerSize.height);
[self.view setAlpha:0.0f];
[self.view setCenter:loc];
[self.view setBounds:CGRectMake(0, 0, 0, 0)];
} else {
newCenter = loc;
newBounds = CGRectMake(0,0,1,1);
}
const CGFloat animDur = 0.3f;
[UIView transitionWithView:self.view
duration:animDur
options:UIViewAnimationOptionTransitionNone|UIViewAnimationOptionCurveEaseOut
animations:^{
self.view.alpha = newAlpha;
self.view.center = newCenter;
self.view.bounds = newBounds;
}
completion:nil];
}
I've already tried animating just the frame, rather than bounds and center, but the result was identical.
Does anyone know why this is happening, and how I can overcome this problem?
Many thanks for your time.
from the docs:
UIViewAnimationOptionTransitionNone -
An option for specifying that no transition should occur.
try one of:
UIViewAnimationOptionTransitionFlipFromLeft
UIViewAnimationOptionTransitionFlipFromRight
UIViewAnimationOptionTransitionCurlUp
UIViewAnimationOptionTransitionCurlDown
Edit:
Or if you're just looking to animate those values, try
[UIView animateWithDuration:(NSTimeInterval)duration
animations:(void (^)(void))animations
completion:(void (^)(BOOL finished))completion];
I'm making a video player for iPad and I'm having some trouble animating the rotation properly. Usually I deal with rotation by setting the auto rotation mask, but since I'm working with a video player I want to preserve the aspect ratio and I'm not sure how I would do that with auto rotation mask.
I did a quick and dirty solution without animation just to get the correct behavior:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
moviePlayer.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width*0.75);
}
It works correctly, but it's not pretty. I'm currently preparing the app for a demo, so now working correctly isn't enough, it has to be pretty.
I tried the following and I think you can guess why it doesn't work:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[UIView animateWithDuration:duration animations:^{
moviePlayer.view.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width*0.75);
}];
}
That's right, self.view.frame hasn't been updated yet.
Any advice on how to deal with this, without hard coded frames?
There may be a cleaner way to do this, but I calculate what the new frame should be using the current one, and the new orientation:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
CGSize size = self.view.frame.size;
CGRect newRect;
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
newRect = CGRectMake(0, 0, MIN(size.width, size.height), MAX(size.width, size.height));
} else {
newRect = CGRectMake(0, 0, MAX(size.width, size.height), MIN(size.width, size.height));
}
[UIView animateWithDuration:duration animations:^{
player.view.frame = newRect;
}];
}