playing youtube video inside uiwebview. How to handle the "done" button? - iphone

I have a uiwebview that plays a youtube video. How can I handle the done button action?
Right now, when I tap the done button it changes back to my app main menu (not the menu that was supposed to dismiss to) and it just freezes. Can anyone help me please?
Ps: the menu where the uiwebview is located, was previously presented modally.

The YouTube plug-in player is itself a modal view controller. It is returning to its presentingViewController when the done button is pressed. Its presentingViewController is not your modal view controller but is instead the viewController that called [presentModalViewController:animated:] to present your modal view controller. Since the original modal view controller is still active, the app behaves badly.
To fix the problem,
1) Track whether the modal view controller has been presented but not dismissed.
2) In the viewDidAppear method of the presenting view controller, if the modal view controller was presented and not dismissed, dismiss and present it again.
For example, in controller that is presenting the modal web view controller:
- (void) presentModalWebViewController:(BOOL) animated {
// Create webViewController here.
[self presentModalViewController:webViewController animated:animated];
self.modalWebViewPresented = YES;
}
- (void) dismissModalWebViewController:(BOOL) animated {
self.modalWebViewPresented = NO;
[self dismissModalViewControllerAnimated:animated];
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.modalWebViewPresented) {
// Note: iOS thinks the previous modal view controller is displayed.
// It must be dismissed first before a new one can be displayed.
// No animation is needed as the YouTube plugin already provides some.
[self dismissModalWebViewController:NO];
[self presentModalWebViewController:NO];
}
}

This thread is very useful and help me to find the problem!
The answer of lambmj works fine, but I found a better way.
In presenting view controller:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if (self.presentedViewController) {
UIViewController *vc = self.presentedViewController;
[vc dismissModalViewControllerAnimated:NO];
[self presentModalViewController:vc
animated:NO];
}
}
Hope this helps!

#Gdx Wu
#lambmj
Thanks for your methods, they work fine. But there is some small problem that after clicking the done button & jumping directly to the presenting view controller, we need to dismiss the presented modal view controller and present it again, which would bring some dither(like flash) between these view controller switches.
Based on this, I highly recommend #IsaacCisneros 's method which would switch seamlessly.

Simply remove UIWebView when it enters full screen; add back UIWebView when it exit full screen. Sample code below assuming a UIViewController with subview of UIWebView, and your UIWebView should have youtube iframe.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Add observer for "Done" button click
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerWillExitFullscreen:)
name:#"UIMoviePlayerControllerWillExitFullscreenNotification"
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerDidEnterFullscreen:)
name:#"UIMoviePlayerControllerDidEnterFullscreenNotification"
object:nil];
}
- (void)viewDidDisappear:(BOOL)animated {
// Remove observers for "Done" button click
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
}
- (void)playerWillExitFullscreen:(NSNotification *)notification {
// Before exit full screen, add back UIWebView that have been removed earlier
[self.view addSubview:self.webView];
}
- (void)playerDidEnterFullscreen:(NSNotification *)notification {
if (self.presentingViewController) { // UIWebView is presenting the build-in movie player controller
[self.webView removeFromSuperview]; // Built-in movie player controller is already entering full screen mode
}
}

Related

ModalViewController not in the window hierarchy

After a long period of trying and searching the Internet and StackOverflow I could not find the answer I need.
My Problem is a warning:
Warning: Attempt to present <PAPasscodeViewController: 0x81cc8a0> on <ServerViewController: 0x75864b0> whose view is not in the window hierarchy!
I am using a Custom Control called "PAPasscodeViewController", the thing itself is working but when I try to display the view on the ApplicationDidBecomeActive method it displays this warning in the Consoleoutput.
I am using this method to keep track of the Notification:
[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(wait)
name:UIApplicationDidBecomeActiveNotification object:nil];
my -(void)wait is containing this:
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
NSLog(#"waiting");
[self performSelector:#selector(enterPasscode) withObject:nil afterDelay:.3f];
The App is having a RootViewController and a GeneralViewController, if the User already downloaded a Config package the GeneralViewController gets pushed in after starting as a modalView like this (in the viewDidLoad):
GeneralView = [[GeneralViewController alloc] initWithNibName:#"GeneralViewController" bundle:[NSBundle mainBundle]];
GeneralView.modalTransitionStyle=UIModalTransitionStyleCrossDissolve;
[self presentViewController:GeneralView animated:YES completion:nil];
In the GeneralView the User has more Options to open new Views through Buttons and they get pushed in through IBActions like the GeneralViewController.
So the Problem is occuring when this happens:
I am starting the App, Config Package was already installed and the User wants to track his ServerData on "ServerViewController", so he touches the appropriate Button for this.
Then the View gets pushed in (its now RootViewController (managed by AppDelegate)-> GeneralViewController(pushed in)-> ServerViewController(pushed in)), everything works fine.
Now when the User goes back to his Homescreen I am closing the modal View "ServerViewController" as follows:
-(void)viewDidAppear:(BOOL)animated{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(close:)
name:UIApplicationDidEnterBackgroundNotification object:nil];}
-(IBAction)close:(id)sender{
[self dismissViewControllerAnimated:YES completion:nil];
}
so when the App enters Backgrounding the ServerViewController gets dismissed, after resuming the App the GeneralViewController is now the active View Controller, and in his -(void)viewDidAppear I am calling the -(void)wait from above, it calls this function:
- (void)enterPasscode{
PAPasscodeViewController *passcodeViewController = [[PAPasscodeViewController alloc] initForAction:PasscodeActionEnter];
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
passcodeViewController.backgroundView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];
}
passcodeViewController.delegate = self;
passcodeViewController.passcode = [configArray objectAtIndex:3];
passcodeViewController.simple = YES;
[self presentViewController:passcodeViewController animated:YES completion:nil];
}
This is working fine but then I am getting the annoying warning from above (here again so you dont have to scroll up)
Warning: Attempt to present <PAPasscodeViewController: 0x75d1c10> on <ServerViewController: 0x818b390> whose view is not in the window hierarchy!
actually this is confusing because I think my GeneralViewController is now the Active ViewController again...
Maybe I am just blinded by the simplicity of this Problem... but maybe someone here can help me understand.
I did NOT find any solution in any other post here in StackOverflow or other sites concerning that exact problem!
You have to remove self as observer when your ServerViewController is not shown. Add the following code to ServerViewController:
- (void)viewDidDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

How to refresh tab bar content upon reopening the app from home screen? (iOS / Xcode)

for all of my view controller.m I have the majority of my code in:
- (void)viewDidAppear:(BOOL)animated
So, each time I switch between tab bars all of the info in each view refreshes. (which is good!) Although, when I open the app from the home screen the tab won't update...I have to switch to another tab and back again to get it to load.
Any solutions?
You need to sign up for a notifications to handle it. Register each tab for the notification and a method to handle it. Then just perform your viewDidAppear. It works like a charm.
-(void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}
-(void)becomeActive:(NSNotification *)notification {
// only respond if the selected tab is our current tab
if (self.tabBarController.selectedIndex == 0) { // Tab 1 is 0 index, Tab 2 is 1, etc
[self viewDidAppear:YES];
}
}
Maybe you can invoke all your refreshing code in
(void)applicationDidBecomeActive:(UIApplication *)application
{
}
this method is in your AppDelegate.
Try putting this in the view controller's m file:
- (IBAction)done:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}

Switching to another view on the UITabBarController and then activating a selector

I've got a button on one of my views and I want it to open another view from the tab bar (the view has already been loaded by the app delegate) and then activate one of that view's selectors, which opens a UIActionSheet. This is what I'm doing so far for switching to the other view:
- (void)btnOpenOtherViewPressed:(id)sender
{
[self.tabBarController setSelectedIndex:4];
}
This brings me to the other window, but I can't find a way of sending a signal to the other view controller saying I want to open the UIActionSheet when switching to the view by pressing that button rather than using the tab bar.
You can use notification for this message passing:
- (void)btnOpenOtherViewPressed:(id)sender
{
[self.tabBarController setSelectedIndex:4];
[[NSNotificationCenter defaultCenter] postNotificationName:#"btnOpenOtherViewPressed" object:nil];
}
Add this code to destination view in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(showActionSheet:) name:#"btnOpenOtherViewPressed" object:nil];
And add this method:
-(void)showActionSheet:(NSNotification *)notification{
}

Dismiss UIActionSheet before device rotate?

In portaint Actionsheet show in tabbar. In landscape - in window. I heed do remove UIActionSheet from tabbar before rotate, for after rotate show in wondow.
Inside – willRotateToInterfaceOrientation:duration dismiss action sheet dont work.
You can use NSNotification for this. Add this notifier in your viewdidload file you willl get notify when orientation is going to change:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(OrientationChanged:)
name:#"UIDeviceOrientationDidChangeNotification"
object:nil];
…add this method:
-(void)OrientationChanged
{
}
See NSNotification class reference.
Me i dismiss before rotation and show after, then the UIActionSheet is replaced at middle;
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[APP.validSave dismissWithClickedButtonIndex:1 animated:NO];
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
[APP.validSave showInView:APP.navController.view];
}

Activity indicator in a UITabBar application on the iPhone

I have a UITabBar + UINavigationController application which often needs data from the internet. Sometimes it takes quite a while before it gets it, so I would like to show an activity indicator.
What I was trying is to add a activityView to my window in my applicationDidFinishLaunching method:
[window addSubview:tabBarController.view];
fullscreenLoadingView.hidden = YES;
[window addSubview:fullscreenLoadingView];
And then I add the application delegate as a observer to the default notification center:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(startFullscreenLoading:) name:#"startFullscreenLoading" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(stopFullscreenLoading:) name:#"stopFullscreenLoading" object:nil];
and implement the methods:
- (void)startFullscreenLoading:(NSNotification *)notification {
fullscreenLoadingView.hidden = NO;
}
- (void)stopFullscreenLoading:(NSNotification *)notification {
fullscreenLoadingView.hidden = YES;
}
When I then use this directly in the applicationDidFinishLaunching method the loading indicator view shows upp as expected:
[[NSNotificationCenter defaultCenter] postNotificationName:#"startFullscreenLoading" object:self];
But when I use it from one of the navigation controllers the startFullscreenLoading: method is called but I don't see the loading indicator view. Why is that?
Are you loading your data on a background thread? Your main thread will be blocked & won't be able to redraw or process any other events.
The most likely thing I can guess is that your indicator view is below some other view. Try
[[fullScreenLoadingView superView] bringSubviewToFront:fullScreenLoadingView]
If that doesn't work, I would suggest breaking inside of -startFullscreenLoading to make sure the fullscreenLoadingView is still valid.
In my app I did this by adding the UIActivityView in IB and making sure it was above everything else (as a top-level object). It's set to be invisible when stopped.
Then in my code I make it appear with [activityIndicator startAnimating] and make it disappear with [activityIndicator stopAnimating];