I have an "AViewController" is root viewController and I have an image is playing animation infinite loop.
- (void)rotateImageView
{
[UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
[self.imageViewSpin setTransform:CGAffineTransformRotate(self.imageViewSpin.transform, M_PI_2)];
}completion:^(BOOL finished){
if (finished) {
[self rotateImageView];
}
}];
}
in viewWillAppear
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(rotateImageView) name:UIApplicationWillEnterForegroundNotification object:nil];
[self rotateImageView];
}
This work great if my application become to active. But when I'm try to presentViewController "CViewController"
[self.navigationController presentViewController: animated: completion:]
And I have Back button on "CViewController"
[self dismissViewControllerAnimated:YES completion:^{
[[NSNotificationCenter defaultCenter] postNotificationName:#"checkIsPresent" object:self];
}];
After returning to "AviewController",animation stops working.
How to solve this issue.
Thank you.
Edit.
Work now I just put [self rotateImage]; in method from postNotification.
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(rotateImageView) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkPresentView) name:#"checkIsPresent" object:nil];
[self rotateImageView];
}
-(void)checkPresentView{
//isModalView = false;
[self rotateImageView];
}
Related
I have very strange issue which happens when keyboard appears they should shift textfield. It's work nice until I open and close Control Center (Video link)
In video I open and close Control Center fast and immediately press to textField, but if open and close Control Center and await around one second, it will work correctly.
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardShow:) name: UIKeyboardWillChangeFrameNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardHide:) name:UIKeyboardWillHideNotification object:nil];
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillResignActiveSelector:) name:#"applicationWillResignActive" object:nil];
}
- (void) viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void) applicationWillResignActiveSelector:(id)object {
[self dismissKeyboard];
}
- (void)dismissKeyboard {
if (self.textInput.isFirstResponder) {
[self.textInput resignFirstResponder];
}
}
- (void)keyboardShow:(NSNotification *)notification {
CGRect keyboard = [[info valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval duration = [[info valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.view.center = CGPointMake(self.centerView.x, self.centerView.y - heightKeyboard);
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, heightKeyboard - self.view.safeAreaInsets.top, 0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, self.tableView.contentInset.bottom, self.tableView.bounds.size.width - 10);
[self.view layoutIfNeeded];
}
- (void)keyboardHide:(NSNotification *)notification
{
NSDictionary *info = [notification userInfo];
NSTimeInterval duration = [[info valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
self.tableView.delegate = nil;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
self.view.center = self.centerView;
self.chatBackgroundTopConstraint.constant = 0;
[self.view layoutIfNeeded];
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, self.tableView.contentInset.left, self.tableView.contentInset.right, self.tableView.bounds.size.width - 10);
} completion:^(BOOL finished) {
self.tableView.delegate = self;
}];
[self.tableView reloadData];
}
For some reason, UIKeyboardWillHideNotification is being executed twice in my below code - I haven't a clue as to why. I know this because my NSLog ("Closed!") appears twice in my console. Am I missing something obvious (and no, I don't have UIKeyboardWillHideNotification pasted somewhere in my code a second time).
-(void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)handleKeyboard:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 3;
[value getValue:&duration];
if (aNotification.name == UIKeyboardWillShowNotification) {
self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight);
[self moveCustomView:YES duration:duration];
}
if (aNotification.name == UIKeyboardWillHideNotification) {
/** KEYBOARD HIDE **/
self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight); self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight);
[self moveCustomView:NO duration:duration];
NSLog(#"CLOSED!");
}
}
Make sure to remove observers in viewDidDisappear as , view controller may be not reallocated from some reason and code in viewDidLoad is executed twice as observer is added twice
// Objective c
- (void)viewWillDisappear:(BOOL)paramAnimated{
[super viewWillDisappear:paramAnimated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
// Swift
override func viewDidDisappear(_ animated: Bool)
{
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
Be sure to remove the observer from the dealloc method. If you do not remove it and its memory is not released, it will listen for keyboard behavior on other pages. In addition, you should not add the same notification twice to the same observer.
Instead of Using same method for Hide and show notification. You can use two different Methods.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
Now, for Change your frame You can use following code
NSDictionary* info = [aNotification userInfo];
CGSize *kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -kbSize.height);
Please, try it like this:
What I did:
• moved subscription to viewWillAppear
• added "unsubscribe" in viewWillDisappear
• added "unsubscribe" in dealloc (shouldn't be related to your issue, but that's the right way to do it still)
• replaced == with isEqual in your handler (also not related to your issue, most likely).
There may be some typos there. Sorry, if that's the case.
-(void)viewWillAppear {
[super viewWillAppear];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillChange:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleKeyboard:) name:UIKeyboardWillShowNotification object:nil];
}
-(void)viewDidLoad {
[super viewDidLoad];
//Leaving this method here just to point out that everything was moved to viewWillAppear
}
- (void)handleKeyboard:(NSNotification*)aNotification{
NSDictionary* info = [aNotification userInfo];
NSValue* value = [info objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval duration = 3;
[value getValue:&duration];
if ([aNotification.name isEqual: UIKeyboardWillShowNotification]) {
self.upView.frame = CGRectOffset(self.upView.frame, 0, -self.keyboardHeight);
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, -self.keyboardHeight);
[self moveCustomView:YES duration:duration];
}
if ([aNotification.name isEqual: UIKeyboardWillHideNotification]) {
/** KEYBOARD HIDE **/
self.upView.frame = CGRectOffset(self.upView.frame, 0, self.keyboardHeight);
self.tableView.frame = CGRectOffset(self.tableView.frame, 0, self.keyboardHeight);
[self moveCustomView:NO duration:duration];
NSLog(#"CLOSED!");
}
}
-(void)unsubscribe {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)viewWillDisappear {
[super viewWillDisappear];
[self unsubscribe];
}
-(void)dealloc {
[self unsubscribe];
}
I want to raise my keyboard when i press on a determinate UITextField, so I create a touch down action, but at the first call it doesn't work, by second call it work fine.
here's the code (naturally keyboardSize is a global variable with CGSize type):
- (void)viewWillAppear:(BOOL)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 {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)viewWillDisappear:(BOOL)animated {
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
}
- (void)keyboardWillHide:(NSNotification *)notification {
[self moveFrameToVerticalPosition:0.0f forDuration:0.3f];
}
- (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration {
CGRect frame = self.view.frame;
frame.origin.y = position;
[UIView animateWithDuration:duration animations:^{
self.view.frame = frame;
}];
}
- (IBAction)insert:(id)sender {
float newVerticalPosition = - keyboardSize.height;
[self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.0f];
}
In keyboardWillShow: add:
[self moveFrameToVerticalPosition:-keyboardSize.height forDuration:0.0f];
You don't really need insert:.
I'm using MPMoviePlayerViewController to play video. In my app I am playing video(s) that are in the app, using the standard MPMoviePlayerController class. It works fine on iOS 7 and 8
The first time around around this works great, however after watching 1 video if you try and watch something else the app crashes on MPMoviePlayerController's play method with the error:
: CGContextSaveGState: invalid context 0x0
: CGContextClipToRect: invalid context 0x0
: CGContextTranslateCTM: invalid context 0x0
: CGContextDrawShading: invalid context 0x0
: CGContextRestoreGState: invalid context 0x0
*** -[MPMoviePlayerController retain]: message sent to deallocated instance 0x1e5718b0
I can not figure out why this is happening.
Here is my code:
AFPlayerViewController.h
#property (strong, nonatomic) MPMoviePlayerViewController *playerViewController;
- (id)initWithContentURL:(NSString*)movieUrl
andSubtitlePath:(NSString*)subPath
withTypeServer:(NSString*)serverType
withName:(NSString*)name
withEpisodeId:(NSString*)episodeId
withFilmId:(NSString*)filmId
withDuration:(NSInteger)targetDuration
withSeason:(NSString*)seasonId;
AFPlayerViewController.m
#synthesize playerViewController;
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (_movieURL) {
self.playerViewController = [[MPMoviePlayerViewController alloc] initWithContentURL: _movieURL];
self.playerViewController.moviePlayer.initialPlaybackTime = -1.f;
self.playerViewController.moviePlayer.shouldAutoplay = NO;
[self.playerViewController.moviePlayer setControlStyle:MPMovieControlStyleNone];
[self.playerViewController.moviePlayer setFullscreen:NO animated:YES];
self.playerViewController.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
[self.playerViewController.view setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.view addSubview:self.playerViewController.view];
[NSLayoutConstraint alightTopBotLeftRight:self.playerViewController.view inView:self.view];
[self.playerViewController.moviePlayer prepareToPlay];
[self.playerViewController.moviePlayer play];
[self receiveNotificationPlayerViewController];
}
}
- (void)receiveNotificationPlayerViewController {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(durationAvailable:)
name:MPMovieDurationAvailableNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(loadStateDidChange:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playbackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(sourceTypeAvailable:)
name:MPMovieSourceTypeAvailableNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(readyForDisplay:)
name:MPMoviePlayerReadyForDisplayDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationDidChange:)
name:UIDeviceOrientationDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didFinishAVideo:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerViewController.moviePlayer];
}
- (void) durationAvailable: (NSNotification*) notification {
NSLog(#"1");
}
- (void) loadStateDidChange: (NSNotification*) notification {
NSLog(#"2");
if ([self.playerViewController.moviePlayer loadState] != MPMovieLoadStateUnknown) {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:nil];
}
}
- (void) playbackStateDidChange: (NSNotification*) notification {
NSLog(#"3");
switch (self.playerViewController.moviePlayer.playbackState) {
case MPMoviePlaybackStateSeekingForward:
case MPMoviePlaybackStateSeekingBackward:
break;
case MPMoviePlaybackStatePaused: {
NSLog(#"pause");
}
break;
case MPMoviePlaybackStateStopped: {
NSLog(#"stop");
}
break;
case MPMoviePlaybackStateInterrupted:{
NSLog(#"interrupted");
}
break;
case MPMoviePlaybackStatePlaying: {
NSLog(#"playing");
}
break;
default:
break;
}
}
- (void) sourceTypeAvailable: (NSNotification*) notification {
NSLog(#"4");
}
- (void) readyForDisplay: (NSNotification*) notification {
NSLog(#"5");
}
- (void)orientationDidChange: (NSNotification*)notification {
NSLog(#"6");
}
- (void)didFinishAVideo:(NSNotification*)notification {
[self removeNotification];
}
- (void)removeNotification {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMovieDurationAvailableNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMovieSourceTypeAvailableNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerReadyForDisplayDidChangeNotification
object:self.playerViewController.moviePlayer];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIDeviceOrientationDidChangeNotification
object:self.playerViewController.moviePlayer];
}
AppDelegate.h
#property (strong, nonatomic) AFPlayerViewController *player;
AppDelegate.m
+ (AppDelegate *)shareInstance{
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (UIViewController *)currentVisibleController{
id rootController = self.window.rootViewController;
if ([rootController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navigationController = (UINavigationController *)rootController;
return navigationController.topViewController;
}
if ([rootController isKindOfClass:[UITabBarController class]]) {
UITabBarController *tabbarController = (UITabBarController *)rootController;
id topViewController = [tabbarController.viewControllers objectAtIndex:tabbarController.selectedIndex];
if ([topViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navi = (UINavigationController *)topViewController;
return navi.topViewController;
}
return topViewController;
}
return self.window.rootViewController;
}
When I'd like to play a video:
[AppDelegate shareInstance].player = [[AFPlayerViewController alloc] initWithContentURL:link
andSubtitlePath:subtitle
withTypeServer:serverType
withName:nameFilm
withEpisodeId:epObject.episodeId
withFilmId:filmId
withDuration:lastDuration
withSeason:epObject.id_season];
[[AppDelegate shareInstance].currentVisibleController presentViewController:[AppDelegate shareInstance].player animated:NO completion:^{
}];
You may well be getting the error because of notifications being sent to a removed controller object as #Bannings says. Nevertheless, I have a couple of other suggestions that will improve your code (and I am fairly sure will remove the error).
Firstly, the documentation says that you should register for the MPMoviePlayerLoadStateDidChangeNotification and use the loadState method to determine when the movie is ready to start playing. I strongly suggest that you do that.
Secondly, you are instantiating a MPMoviePlayerController every time your view appears. I would suggest that you create a single AFPlayerViewController and a single MPMoviePlayerController. Present the same AFPPlayerViewController whenever you wish to play another movie.
When you first instantiate the MPMoviePlayerController, you will need a a URL, for its init method, but subsequent movies can be started using the contentURL property of MPMoviePlayerController
A side advantage of my suggestion is that it will be very easy for a user to pause a movie, go to a different view, and then quickly resume when they return to the movie view.
Have you called the removeNotification if you try and watch something else? try to add viewDidDisappear:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self removeNotification];
}
I think I see the real problem here: you should be using MPMoviePlayerController not MPMoviewPlayerViewController. Make that change, and see if the crash disappears. My suggestion about loadState should be followed too.
The documentation mentions adding shadows to the controller being animated to show the slide menu. However, instead of a shadow I would like to make the animated view controller to be darker. Is this possible?
I simply created a masking view and presented/removed it on notifications from the slidingviewcontroller. Added some nice fade in and fade out action for effect :) Hope this helps
#import <UIKit/UIKit.h>
UIView *overLayView;
#interface MyViewController : UIViewController {
UIView *overLayView;
}
#end
#implementation MyViewController
- (void)viewDidLoad
{
[super viewDidLoad];
overLayView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
overLayView.backgroundColor = [UIColor blackColor];
}
-(void) viewWillAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(disableView) name:ECSlidingViewUnderLeftWillAppear object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(enableView) name:ECSlidingViewTopWillReset object:nil];
}
- (void)viewWillDisappear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] removeObserver:self name:ECSlidingViewUnderLeftWillAppear object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:ECSlidingViewTopWillReset object:nil];
}
-(void) disableView {
overLayView.alpha = 0;
[self.view addSubview:overLayView];
[UIView animateWithDuration:0.5 animations:^{
overLayView.alpha += kViewHelperUIViewMaskAlpha;
}];
}
-(void) enableView {
[UIView animateWithDuration:0.5 animations:^{
overLayView.alpha -= kViewHelperUIViewMaskAlpha;
} completion:^(BOOL fin){
if(fin){
[overLayView removeFromSuperview];
}
}];
}
#end