Moving animation off screen with scroll view - animation

I have a small animation at the begining of my app, two doors open up horizontally, top and bottom to reveal screen. All good so far, the top section moves off fine, however as i have a scroll view the page is longer than standard, 175000 to be exact. Im usure of how to modify the code to send the bottom png off the screen as at the moment its stuck going to where the standard screen would end. Could someone advise? Ive tried so far manually adding the height after self.view.size.height; but that didn't work, im assuming its around there somewhere I should be altering
CGRect doortopFrame = doortop.frame;
doortopFrame.origin.y = -doortopFrame.size.height;
CGRect doorbottomFrame = doorbottom.frame;
doorbottomFrame.origin.y = self.view.bounds.size.height;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0];
[UIView setAnimationDelay:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
doortop.frame = doortopFrame;
doorbottom.frame = doorbottomFrame;
[UIView commitAnimations];

Fixed this, changing bottom animation to origin.X does the trick

Related

iOS 8 animation bug

I have a simple method for animate view.
-(void)animateSelf
{
CABasicAnimation * animation;
animation = [CABasicAnimation animationWithKeyPath:#"position.y"];
// settings ...
[self.view.layer addAnimation:animation forKey:#"position.y"];
animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
// settings ...
[self.view.layer addAnimation:animation forKey:#"transform.rotation.z"];
[UIView animateWithDuration: 1.0 animations:^{
CGRect rect = self.view.frame;
rect.origin.y += 800;
self.view.frame = rect;
} completion:nil];
}
For iOS 7 it worked well. But for iOS 8 animation behaves unpredictably. Is there a way to combine these animations for iOS 8?
I tried to replace animateWithDuration: by another CABasicAnimation, but it did not help.
The view.frame logs are correct, but the animation of view.frame jumps out of obscure origin.
After removing CABasicAnimation for position.y (the first one) bug is gone.
You have three animations:
You animate the layer's position
You animate the layer's transform
You animate the view's frame which in turn animates the layer's position.
Animations 1 and 3 collide.
On iOS 7 the behavior is that animation 3 cancels animation 1.
On iOS 8 the behavior is that animations 1 and 3 run concurrently ("Additive Animations").
I suggest you just remove animation 1 and also check out the related WWDC 2014 video (I think it was Building Interruptible and Responsive Interactions).
What worked for me was disabling autolayouts on the view and THE SUBVIEWS of the view I was animating at some point before doing the animation. Disabling autolayouts from the storyboard was not enough in iOS8.
[viewToAnimate removeFromSuperview];
[viewToAnimate setTranslatesAutoresizingMaskIntoConstraints:YES];
//addSubview again at original index
[superView insertSubview:viewToAnimate atIndex:index];
This example might help you, I wish I had discovered it before wasting hours. Rather than animate the frame, animates its contraints. Click on the auto layout constraint you would like to adjust (in interface builder e.g top constraint). Next make this an IBOutlet;
#property (strong, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;
Animate upwards;
self.topConstraint.constant = -100;
[self.viewToAnimate setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.viewToAnimate layoutIfNeeded];
}];
Animate back to original place
self.topConstraint.constant = 0;
[self.viewToAnimate setNeedsUpdateConstraints];
[UIView animateWithDuration:1.5 animations:^{
[self.viewToAnimate layoutIfNeeded];
}];
Originally posted by me here
So you would adjust the constraint for self.view.frame in your example.
I also got an issue of little nasty differences between iOS7 and iOS8 animation.
In most cases it was broken it was either:
single combination of Scale, Transform and Rotate CGAffineTransforms - the result was dependant on iOS version
or complex sequence of animations on different views - some views were 'reseting' their positions before commencing a new piece of animations. About 5% of animation pieces were affected.
I'm pretty sure there were no simultaneous animations on the problematic views.
Autolayout and constraints suggestions did not help (moreover, all animated views were create in code as autolayout interfered with animation a lot even before iOS8).
What turned out to be a universal solution for both problems is to put the problematic views into a wrapper view and use it to split-off Rotation animation or to do the animation that causes 'reset' effect. Now it functions the same in 7.1.1 and 8.1.1.

Animation in UISlider is skipped on iOS 7

I have a slider that is functioning as 2 sliders, according to the audio played - when 1 type of audio (some kind of vocal guidance) is disabled, a music is played, and the slider controls the music's volume.
When changing roles, the slider changes positions, according the its role (guidance - upper in the view, music - lower) and adjusts the its value (the volume) to a saved volume value for that type of sound (guidance sound or music sound).
The type of effect I was looking for was -
Move the slider to its new location, using [UIView
animateWithDuration]
When the slider reaches its location, change its value to reflect the
volume, again, using [UIView animateWithDuration].
First, I wrote it like that -
[UIView animateWithDuration:0.3
animations:^{self.volumeSlider.frame = sliderFrame;}
completion:^(BOOL finished){
[UIView animateWithDuration:0.3
animations:^{self.volumeSlider.value = newValue;}
];
}];
Which worked very well in the iOS 6 simulator (using Xcode 4.6.3), but when changing to my phone, running iOS 7, the slider changed its position and then the slider's value jumped to the new value.
The same problem occurred again when running in the iOS 7 simulator that comes with Xcode 5, so I assume it's an iOS 7 problem.
I did some experiments, all with different results:
I tried setting the volume using '[UIView animateWithDuration:0.3 delay:0.3 options: animations: completion:]', meaning, not in the completion part, but the same thing happend.
When putting just the 2 animations one after another (each as separate animation, each without a delay, one after another) the result will vary according to the order of the animations.
[UIView animateWithDuration:0.3 animations:^{self.volumeSlider.value = newValue;}];
[UIView animateWithDuration:0.3 animations:^{self.volumeSlider.frame = sliderFrame;}];
Will move both the slider and its value together, both animated, while
[UIView animateWithDuration:0.3
animations:^{self.volumeSlider.frame = sliderFrame;}];
[UIView animateWithDuration:0.3
animations:^{self.volumeSlider.value = newValue;}];
Will move the slider's position, and then change its value without animation.
I tried calling the 2nd animation through
[self performSelector:#selector(animateVolume:) withObject:nil afterDelay:0.3];
And again - the slider moved, and then the value changed at once.
WHY, OH WHY??
If it helps, this is the description of the slider, BEFORE the first animation -
<UISlider: 0xcc860d0; frame = (23 156; 276 35); autoresize = RM+BM;
layer = <CALayer: 0xcc86a10>; value: 1.000000>
And After the first animation ended -
<UISlider: 0xcc860d0; frame = (23 78; 276 35); autoresize = RM+BM;
animations = { position=<CABasicAnimation: 0xbce5390>; };
layer = <CALayer: 0xcc86a10>; value: 0.000000>
Notice the animations section, that shouldn't be there by now (the description is logged from [self animateVolume] which is called with a delay of .3 seconds).
I know its a weird problem, but I would very much appreciate help with it.
Thank :)
Dan
UPDATE
As Christopher Mann suggested, changing the value in the UIView:animationWithDuration is not the official way of using it, and the correct way would be to use UISlider's setValue:animated.
However, for the people who will encounter such problem in the future - it seems that iOS 7 has some difficulties with that method, such that it is not animated in some cases (I think it will not be animated if the project was started in Xcode < 5).
The problem and its solution are described here.
My code that solved this problem is:
[UIView animateWithDuration:0.3
animations:^{self.volumeSlider.frame = sliderFrame;}
completion:^(BOOL finished){
[UIView animateWithDuration:1.0 animations:^{
[self.volumeSlider setValue:newValue animated:YES];
}];
currentSliderMode = mode;
}];
If you want to animate the change in slider value you should use setValue:animated: instead of setting .value directly. Changing volumeSlider.value inside the UIView animation block is likely interfering the the animation.

ImageView Animation

I have 1 image that i want it to move across the screen. in my case its an image of a little motorcycle that rides form left to right across the screen.
I there any way to take this one image & make it move one step every time for make it like animation image? instead of taking a lot of pictures frame by frame and make animation from it because in my case i have 367 pictures & it makes the project very big.
Thanks.
#property(nonatomic, strong) UIImage *animation;
You can display it in an UIImageView and animate the view itself:
UIImageView *imgView = [[UIImageView alloc] initWithImage:motorcycleImage];
[self.view addSubview:imgView];
[imgView release];
And when you want to animate it:
[UIView beginAnimations:NULL context:NULL];
[UIView setAnimationDuration:1.0];
CGRect rect = imgView.rect;
rect.origin.x += 320 - rect.size.width;
// EDIT: how to put the view on the bottom of the screen
rect.origin.y += 480 - rect.size.height;
imgView.rect = rect;
[UIView commitAnimations];
Hope it helps.

NSScrollView scroll bars are of the wrong length

I have a Cocoa window, whose content view contains an NSScrollView that, in turns, contains a fixed-size NSView.
Upon launching the program, the scroll bars displayed initially are too small, as if the content size was much larger than it actually is:
When I start playing with, e.g., the vertical scroll bar, and bring it back to the original position at the top, it gets resized to its expected size (which corresponds to the ratio of scroll view and content view sizes):
(Notice the horizontal bar, which still has incorrect size. If I then play with it, and bring it back to its leftmost position, it gets resized to the correct size.)
I also encountered the same problem, I have searched everywhere but it seems no one else experiences this problem. Fortunately I found a hack which solves the problem.
What I did notice was that when the window is resized or maximized the scrollbars resize to the expected size (autoresizing has to be enabled). This is because when the window resizes so does the scrollview and the length of the scroll bars gets recalculated and is calculated correctly. Possibly due to some bug the scroll bar lengths are not calculated correctly on initialization. Anyway to fix the problem, in your application delegate create an outlet to your window. Override the "applicationDidFinishLaunching" method and inside it call the method "frame" on the window outlet, which returns the current NSRect of the window. Using the returned value add one to the size.width and size.height. The call the method setFrame with display set to YES. This will resize the window and force the size of the scrollbars to be recalculated.
Here is the code for applicationDidFinishLaunching Below
(void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Get the current rect
NSRect windowRect = [_window frame];`
// add one to the width and height to resize window
windowRect.size.width += 1;
windowRect.size.height += 1;
// resize window with display:YES to redraw window subviews
[_window setFrame:windowSize display:YES];
}
I encountered this issue when modifying an NSTextView textContainer size to toggle line wrapping. Resizing the enclosing view does cause the correct scroll view height to be used, however its a brutal solution.
NSScrollView supports -reflectScrolledClipView. Calling this directly in my case had no effect except when delayed on the runloop:
[textScrollView performSelector:#selector(reflectScrolledClipView:) withObject:textScrollView.contentView afterDelay:0];
The scroller position is correct but there is a scroller redraw. So it looks as if part of the view geometry is calculated when drawing. A better solution is therefore:
NSDisableScreenUpdates();
[textScrollView display];
[textScrollView reflectScrolledClipView:textScrollView.contentView];
[textScrollView display];
NSEnableScreenUpdates();
Building on the answer from jstuxx above, if you don't want the window to visibly resize, try:
NSRect windowRect = [[[self view] window] frame];
windowRect.size.width += 1;
windowRect.size.height += 1;
[[[self view] window] setFrame:windowRect display:YES];
windowRect.size.width -= 1;
windowRect.size.height -= 1;
[[[self view] window] setFrame:windowRect display:YES];
I had to put this code after where I was programmatically adding the scroll view to my interface.

Animating simultaneously window and view frame in Cocoa

I need to animate a view frame size adding 100px of height, but I need the window grow up simultaneously with the view.
I tried with this code :
//resize Window
NSRect winsize = [window frame];
winsize.size.height += 100;
[self.window setFrame:winsize display:YES animate:YES];
//resize View
NSRect viewsize = [myview frame];
viewsize.size.height += 100;
[[myview animator] setFrame:viewsize];
It works but I obtain an ugly effect, Window and View had some delay in resize. Thus, I get the Window frame resizing before than the View frame.
How can I modify my code to make them resizing simultaneously ?
add:
I found this answer but it tdoesn't seems to work for me:
Simultaneously modify window frame and view frame
I found a good solution: using autoresizingMask to mantain min and max Y Margin and allow height resize.
[myview setAutoresizingMask:NSViewHeightSizable];

Resources