I'm a big fan of autolayout, but have always implemented it in Storyboard.
I have a UIView that I want the bottom space constraint to be where the keyboard ends.
I have defined all my constraints, can someone show me how to implement this constraint in code for just the bottom space? And also how to get the value of the keyboard height depending on the specific iDevice and match that to the constraint.
Thanks
Take an outlet of the bottom constraint of the view like this
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *constraintContainerBottom;
and use this
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self setupKeyboard:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self setupKeyboard:NO];
}
- (void)setupKeyboard:(BOOL)appearing
{
if (appearing) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}else{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
}
- (void)keyboardWillShow:(NSNotification*)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
double duration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
int curve = [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
[UIView beginAnimations:#"keyboardShown" context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
self.constraintContainerBottom.constant = keyboardSize.height;
[self.view layoutIfNeeded];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification*)notification
{
double duration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
int curve = [[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
[UIView beginAnimations:#"keyboardHidden" context:nil];
[UIView setAnimationDuration:duration];
[UIView setAnimationCurve:curve];
self.constraintContainerBottom.constant = 0;
[self.view layoutIfNeeded];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
Related
I have had a simple UIView block animation that handles animating a group of text fields into view when the keyboard will show (and animate them back when the keyboard hides). This has worked fine in iOS 6 & 7, but now I'm getting incorrect behavior, and it all points to some change in UIKeyboardWillShowNotification.
I set up an isolated project to test this further on a single text field, with two buttons that call exactly the same methods that are fired for the keyboard's WillShow and WillHide notifications. See the results in this video:
Video example
This seems like a bug to me, or it might be a change to the behavior of this notification. Does anyone know if this is intended and/or what can be done about it?
Here is the relevant code:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
self.textField.frame = CGRectOffset(self.textField.frame, 0.f, _destY - _origY);
}];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
[UIView animateWithDuration:0.3 animations:^{
self.textField.frame = CGRectOffset(self.textField.frame, 0.f, _origY - _destY);
}];
}
Portrait App, loads video that displays in landscape.
in iOS7 all works fine (minor fix this is iOS6 too) but in iOS8 the statusbar, although showing in landscape actually shows at the size of a portrait statusbar so it only occupies the top left hand 60% of the video (if holding device in landscape).
The code I'm using is as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
[planTitleLabel setText:[[ProgrammeHandler sharedHandler]
stringForElement:kPlanStringElementPlanTitle
onDay:0 inPlan:selectedPlan]];
}
- (NSUInteger)supportedInterfaceOrientations{
return 0;
}
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([[UIDevice currentDevice].systemVersion floatValue] < 7.0) {
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:FALSE];
[[UIApplication sharedApplication] setStatusBarHidden:TRUE withAnimation:UIStatusBarAnimationNone];
}else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0 && [[UIDevice currentDevice].systemVersion floatValue] < 9.0) {
[[UIApplication sharedApplication] setStatusBarHidden:TRUE];
}
NSString *moviePath = [[ProgrammeHandler sharedHandler] pathForAsset:kAssetVideoIntro onDay:0 forPlan:selectedPlan];
CGSize screenBounds = [[UIScreen mainScreen] bounds].size;
[whiteFadeView setFrame:CGRectMake(0, 0, screenBounds.width, screenBounds.height)];
NSURL *videoURL = [NSURL fileURLWithPath:moviePath];
moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];
[[moviePlayer view] setBackgroundColor:[UIColor blackColor]];
[moviePlayer setControlStyle:MPMovieControlStyleNone];
[moviePlayer setScalingMode:MPMovieScalingModeAspectFill];
//For viewing partially.....
moviePlayer.view.transform = CGAffineTransformMakeRotation(M_PI/2);
[moviePlayer setScalingMode:MPMovieScalingModeAspectFill];
[movieView setAlpha:0];
[moviePlayer.view setFrame:[movieView frame]];
moviePlayer.view.backgroundColor = [UIColor blackColor];
[movieView addSubview:moviePlayer.view];
[moviePlayer prepareToPlay];
[moviePlayer play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playbackFinished:)
name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(hideControl)
name:MPMoviePlayerLoadStateDidChangeNotification
object:moviePlayer];
[UIView animateWithDuration:0.5f delay:0.50f
options:UIViewAnimationOptionCurveEaseIn
animations:^{[movieView setAlpha:1];} completion:^(BOOL fin){ }];
}
- (void) hideControl {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerNowPlayingMovieDidChangeNotification
object:moviePlayer];
[moviePlayer setControlStyle:MPMovieControlStyleFullscreen];
}
I did see this question but don't think it applies in my case.
iphone: rotation in mpmovieplayercontroller?
Does any one know how to restore the statusbar to it's fullscreen 'width'?
Ok, after looking over this again today I noticed that there was an error that iOS7 seems happy with but it was correctly throwing an error in iOS8. For anyone else with the same issue:
The fix is simply to apply the transformation to the moviePlayer itself rather than the subview. e.g.
replace
moviePlayer.view.transform = CGAffineTransformMakeRotation(M_PI/2);
with
movieView.transform = CGAffineTransformMakeRotation(M_PI/2);
When I click “play movie” the mpmovieplayer presents itself for half a second and I see it’s loading movie and the controls are there, but then it returns to main screen without playing the video.
How do I fix this?
Edit:
I have changed code and now the player stays up but is stuck on loading, it doesn’t play movie.
IS the problem: not preparing the movie for play? Or not stopping movie in background and then restarting it?
#import "ViewController.h"
#implementation ViewController
#synthesize moviePlayer;
-(IBAction)grabVid:(id)sender;
{
[self presentModalViewController:imagePicker animated:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[imagePicker setDelegate:self];
imagePicker = [[UIImagePickerController alloc] init];
imagePicker.mediaTypes =
[UIImagePickerController availableMediaTypesForSourceType:
imagePicker.sourceType];
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:imagePicker animated:YES];
{
[imagePicker dismissModalViewControllerAnimated:YES];
}
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
//[imagePicker dismissModalViewControllerAnimated:YES];
}
-(IBAction)playMovie:(id)sender
{
NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
MPMoviePlayerViewController *playercontroller = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
[self.view addSubview:playercontroller.moviePlayer.view];
[playercontroller.moviePlayer setFullscreen:YES animated:YES];
playercontroller.moviePlayer.shouldAutoplay = NO;
[self presentMoviePlayerViewControllerAnimated:playercontroller];
playercontroller.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playercontroller.moviePlayer play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:playercontroller.moviePlayer];
}
- (void)moviePlaybackComplete:(NSNotification *)notification
{
MPMoviePlayerController *moviePlayerController = [notification object];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayerController];
[moviePlayerController.view removeFromSuperview];
//[playercontroller.moviePlayer release];
}
- (void)dealloc {
//[super dealloc];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
-(IBAction) playVideo
{
NSURL *url = [info objectForKey:UIImagePickerControllerMediaURL];
MPMoviePlayerViewController *playercontroller = [[MPMoviePlayerViewController alloc] initWithContentURL:url];
moviePlayer.initialPlaybackTime = 0;
[self presentMoviePlayerViewControllerAnimated:playercontroller];
playercontroller.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
[playercontroller.moviePlayer play];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayBackDidFinish:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
moviePlayer.controlStyle = MPMovieControlStyleDefault;
moviePlayer.shouldAutoplay = YES;
[self.view addSubview:moviePlayer.view];
[moviePlayer setFullscreen:YES animated:YES];
// playercontroller = nil;
}
in my ipad app in viewDidLoad i set up a video in the first view so to have an intro.
In allocation tool i see that allocated memory grow till 120MB when running the video, ok i dont care, but after the video finish i would like that memory to go to 0 again BUT stick to 120MB, what am i doing wrong ?
- (void)viewDidLoad{
NSString *url = [[NSBundle mainBundle]
pathForResource:#"sfed"
ofType:#"mp4"];
playerViewController = [[MPMoviePlayerViewController alloc]
initWithContentURL:[NSURL fileURLWithPath:url]];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:[playerViewController moviePlayer]];
[videoview addSubview:playerViewController.view];
MPMoviePlayerController *player = [playerViewController moviePlayer];
player.view.frame = CGRectMake(1024, 748, 0, 0);
[player setControlStyle:MPMovieControlStyleNone];
[player play];
}
- (void) movieFinishedCallback:(NSNotification*) aNotification {
MPMoviePlayerController *player = [aNotification object];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:player];
[player stop];
[player release];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1];
[videoview setAlpha:0];
[UIView commitAnimations];
[videoview release];
}
Managed to get it on my first view, but doesnt work on second view.
Here's what I did on both view, with only a slight differencs for debugging purposes in console
-(void) viewWillAppear:(BOOL)animated {
//---registers the notifications for keyboard---
// to see if keyboard is shown / not shown
[[NSNotificationCenter defaultCenter]
addObserver: self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:self.view.window];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
}
//---when the keyboard appears---
-(void) keyboardDidShow:(NSNotification *) notification {
if (keyboardIsShown) return;
NSLog(#"Keyboard is visible 1"); // debugger purpose "Keyboard is visible 2" on the second view.
NSDictionary* info = [notification userInfo];
//---obtain the size of the keyboard---
NSValue *aValue =
[info objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect =
[self.view convertRect:[aValue CGRectValue] fromView:nil];
//---resize the scroll view (with keyboard)---
CGRect viewFrame = [scrollview frame];
NSLog(#"%f", viewFrame.size.height);
viewFrame.size.height -= keyboardRect.size.height;
scrollview.frame = viewFrame;
NSLog(#"%f", keyboardRect.size.height);
NSLog(#"%f", viewFrame.size.height);
//---scroll to the current text field---
CGRect textFieldRect = [currentTextField frame];
[scrollview scrollRectToVisible:textFieldRect animated:YES];
keyboardIsShown = YES;
}
//---when the keyboard disappears---
-(void) keyboardDidHide:(NSNotification *) notification {
NSDictionary* info = [notification userInfo];
//---obtain the size of the keyboard---
NSValue* aValue =
[info objectForKey:UIKeyboardFrameEndUserInfoKey];
CGRect keyboardRect =
[self.view convertRect:[aValue CGRectValue] fromView:nil];
//---resize the scroll view back to the original size
// (without keyboard)---
CGRect viewFrame = [scrollview frame];
viewFrame.size.height += keyboardRect.size.height;
scrollview.frame = viewFrame;
keyboardIsShown = NO;
}
//---before the View window disappear---
-(void) viewWillDisappear:(BOOL)animated {
//---removes the notifications for keyboard---
[[NSNotificationCenter defaultCenter]
removeObserver: self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
You are registering for UIKeyboardDidShowNotification and UIKeyboardDidHideNotification notifications, and then deregistering for UIKeyboardWillShowNotification and UIKeyboardWillHideNotification notifications. There's your error.