How to animate rotation of MPMoviePlayerController? - objective-c

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;
}];
}

Related

Hide and show UIView with bottom View filling the space when hidden using autolayout

I have two views on top of one another like so. When I press button, I want to hide the grey view and have the pink view move up into its space. When I press button again, I want the grey view to re-appear and move the pink view back into its original position.
I can accomplish this by doing something like
- (IBAction)toggle:(id)sender {
if (self.top.hidden) {
self.top.hidden = NO;
self.top.layer.frame = CGRectMake(0, 0, 320, 50);
self.bottom.layer.frame = CGRectMake(0, 50, 320, 50);
} else {
self.top.layer.frame = CGRectMake(0, 0, 0, 0);
self.bottom.layer.frame = CGRectMake(0, 0, 320, 50);
self.top.hidden = TRUE;
}
}
However, the general wisdom, from what I understand, regarding autolayout is to not set the frame sizes programmatically in the code. So my question is, how can achieve the same result using autolayout?
It's basically the iPhone version of this question: OS X Cocoa Auto Layout hidden elements
Found the answer courtesy of this question: Animating an image view to slide upwards
In short:
- (IBAction)toggle:(id)sender {
if (self.top.hidden) {
self.top.hidden = NO;
[UIView animateWithDuration:0
animations:^{
self.verticalSpace.constant += 50.0;
[self.view layoutIfNeeded];
}];
} else {
[UIView animateWithDuration:0
animations:^{
self.verticalSpace.constant -= 50.0;
[self.view layoutIfNeeded];
}];
self.top.hidden = TRUE;
}
}
where self.verticalSpace is the constraint set between the bottom view to the top view.

UIButton rotation animation not rotating back with CGAffineTransformMakeRotation

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!

iOS/Objective-C: transitionWithView custom animation block resizes view immediately, not over duration

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];

iOS animation: background continuously moving (game)

I am currently coding an educational game in which I need the background to be continuously moving. I've tried to use blocks (iOS 4), for some reason the result isn't satisfying (even if I specify a linear animation, the image slows down at the end. Any suggestion? Thanks for your help!
soil0 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"soil900.jpg"]];
soil0.frame = CGRectMake(0, 0, [UIScreen mainScreen].applicationFrame.size.width, [UIScreen mainScreen].applicationFrame.size.height);
[UIView animateWithDuration:5.0
delay:0.0
options:UIViewAnimationOptionRepeat | UIViewAnimationCurveLinear
animations:^{
soil0.transform = CGAffineTransformMakeTranslation(0, -450); }
completion:^(BOOL fin) { if (fin)
{
soil0.transform = CGAffineTransformMakeTranslation(0, +450);
}
}];
I think perhaps you are seeing easing. UIViewAnimationCurveLinear is for use with the setAnimationCurve class method. Try using UIViewAnimationOptionCurveLinear instead.

How do I stop a modal view from disappearing when rotating on iPad?

I'm using willRotateToInterfaceOrientation to swap views when my iPad rotates. If I have a modal view or an alert view open when my device rotates and swaps views, the view swaps and the alert disappears and does not reappear, even if the alert is "presented" again later.
Edit:
I've narrowed this problem a bit. When a modal view is presented with UIModalPresentationFullScreen, the modal view "survives" rotations.
What can I do to fix this?
Here is my implementation of willRotateToInterfaceOrientation:
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
//
// Load an alternate view depending on the orientation
//
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
[UIView beginAnimations:#"" context:nil];
[self setView:theLandscapeView];
self.view.bounds = CGRectMake(0, 0, 1024, 768);
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (-90));
[UIView commitAnimations];
}else if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
[UIView beginAnimations:#"" context:nil];
[self setView:theLandscapeView];
self.view.bounds = CGRectMake(0, 0, 1024, 768);
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (90));
[UIView commitAnimations];
}else if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
[UIView beginAnimations:#"" context:nil];
[self setView:thePortraitView];
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (0));
self.view.bounds = CGRectMake(0, 0, 768, 1024);
[UIView commitAnimations];
}else if (toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
[UIView beginAnimations:#"" context:nil];
[self setView:thePortraitView];
self.view.transform = CGAffineTransformMakeRotation(kDegreesToRadians * (180));
self.view.bounds = CGRectMake(0, 0, 768, 1024);
[UIView commitAnimations];
}
}
If I were solving this problem, I would do one of the following
Add the alternate views to a parent view, and not change the view property
Create a design for the views that does not require a full view swap, but rearranges or hides subelements of the view.
Present any modal from the root ViewController of the hierarchy
I would work very hard not to swap out the view entirely for the sake of orientation. It seems like something that will continue to present problems even after you have solved this one.
If you swap views, you should also swap modal views I think.
For example, if you present popover controller - it'll automatically dismissed and then appeared with UI rotation.
Here's an idea: keep you main view constant, but change the subview to your portrait or landscape view. something like:
- (void) willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
// Remove the current subview from the main view
if (self.view.subviews.count) {
[self.view.subviews objectAtIndex:0] removeFromSuperview];
}
// Use your if-else block, but change [self setView:] for [self.view addSubview:]
}
So now when you create your modal, it will be linked to your controller, which now has a constant main view.
Note that I didn't test this, as I'm getting my head back into coding after two weeks off...
Good luck!