MPMoviePlayerController Overlay iOS 6 - objective-c

Having an issue with MPMoviePLayerController with an overlay in iOS6, prior to iOS6 things were working fine.
It seems I can play a movie in full screen, before I had this code:
#interface MovieOverlayViewController : UIViewController
{
UIImageView *skiparrow;
}
#end
#implementation MovieOverlayViewController
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
touchtoskip.frame = CGRectMake( xAdjust,
yAdjust,
touchtoskip.image.size.width / scale,
touchtoskip.image.size.height / scale);
[self.view addSubview:touchtoskip];
}
Then:
overlay = [[MovieOverlayViewController alloc] init];
UIWindow *keyWnd = [[UIApplication sharedApplication] keyWindow];
[keyWnd addSubview:overlay.view];
On my MoviePlayerViewController the view DOES appear. And adds the UIViews, but I see NOTHING anymore.
Really stuck, any suggestions?

I think part of the problem is that you are getting the key window and adding a subview to that, rather than getting the window's view and adding a subview to that.
Have a look at the MoviePlayer sample, which shows how to add a player with subviews to control playback.

Related

iOS7 Autoresize When Switching Views Programmatically

I have googled for a few hours with no luck, so I'm coming to you guys to save me here!
Apparently, I can't find the right information on how exactly to go about doing this (or the best way). I have an app that supports portrait and landscape (no support for upside down though). However, the portrait and landscape views are COMPLETELY different, so I'll need to use two views to represent each. Am I correct in assuming I need 3 viewcontrollers in my storyboard (the main one, and then one for portrait and one for landscape? I was going to use just two but I didn't see how to if I start with the portrait, and then need to load landscape, I would have to delete portrait, which is where my code is?
My viewcontroller has the correct constraints in place to keep the label top center, but when replacing or swapping the views programmatically, it seems the auto-resize doesn't get called. I finally fixed this by resetting the frames on the subviews, but now when the device is flipped upside down, the portrait label is forever shifted to the right. So I'd just like to know the proper way to do this, as I'm sure this can't be it.
As far as code, I have one obj-c viewcontroller class with the following modified methods...
#interface AMBViewController ()
#property (strong, nonatomic) UIViewController *portraitViewController;
#property (strong, nonatomic) UIViewController *landscapeViewController;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
UIApplication *app = [UIApplication sharedApplication];
UIInterfaceOrientation currentOrientation = app.statusBarOrientation;
[self doLayoutForOrientation:currentOrientation];
}
-(void) willAnimateRotationToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[self doLayoutForOrientation:toInterfaceOrientation];
}
-(void) doLayoutForOrientation:(UIInterfaceOrientation)orientation {
if (UIInterfaceOrientationIsPortrait(orientation)) {
self.portraitViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Portrait"];
if (self.landscapeViewController != nil ) {
[self.landscapeViewController.view removeFromSuperview];
self.landscapeViewController = nil;
}
self.portraitViewController.view.frame = self.view.bounds;
[self.view insertSubview:self.portraitViewController.view atIndex:0];
} else {
self.landscapeViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Landscape"];
if (self.portraitViewController != nil ) {
[self.portraitViewController.view removeFromSuperview];
self.portraitViewController = nil;
}
self.landscapeViewController.view.frame = self.view.bounds;
[self.view insertSubview:self.landscapeViewController.view atIndex:0];
}
}
Just to be clear on my storyboard, I have one blank root controller (subclass AMBViewController) and two other view controllers "Landscape" and "Portrait"
I might also mention that the label only gets off in portrait view IF you rotate the device in a full circle (4 right or 4 left rotations). If you go right right (now it's upside down) but then left left, it's still fine. It's only when the screen flips from Right/Left Landscape to Left/Right Landscape that it messes up. Really weird, I know I must be omitting something important.
Any help is greatly appreciated. Thanks!
Solution: After finding a guide located on Apple's Dev Site (finally) I was able to come up with a solution using segues and a modal window. First view controller is portrait, second view controller is landscape, connected by a modal segue. The first view controller has the following modified methods:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
_isShowingLandscapeView = NO;
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
-(void) orientationChanged:(NSNotification *)notification {
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
if (UIInterfaceOrientationIsPortrait(orientation) && _isShowingLandscapeView
&& orientation != UIInterfaceOrientationPortraitUpsideDown) {
[self dismissViewControllerAnimated:NO completion:nil];
_isShowingLandscapeView = NO;
} else if (UIInterfaceOrientationIsLandscape(orientation) && !_isShowingLandscapeView ) {
[self performSegueWithIdentifier:#"ShowLandscape" sender:self];
_isShowingLandscapeView = YES;
}
}
Thanks to all who might have looked into this!

In UIViewController's code, [self.subViewGrid setNeedsDisplay] not calling -drawRect

I have an iPad app, using Storyboards, XCode 4.6 and iOS 6.1. I have a scene that contains a UIViewController. Inside that UIViewController, I have a UIScrollController, all created using IB. Programmatically, in viewDidLoad I created two (2) UIViews (one called subViewGrid, the other called subViewData) and added them to the UIViewController; they both display correctly in the Simulator. Here's the code:
- (void)viewDidLoad {
[super viewDidLoad];
// notify me when calendar has been tapped and CFGregorianDate has been updated
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(calendarTapNotification:)
name:#"calendarDateSelected" object:nil ];
// UIScrollVIew settings
CGSize scrollableSize = CGSizeMake(760, 1379); // set size of scheduleView
[self.schedScrollView setContentSize:scrollableSize];
self.schedScrollView.contentInset = UIEdgeInsetsMake(0,0,44,44); // allow for scroll bar
self.schedScrollView.directionalLockEnabled = YES; // prevents diagonal scrolling
// create a sub-view to hold the appointment GRID
CGRect frame = CGRectMake(0,0,760,1390); // 110,48,760,1390
subViewGrid = [[UIView alloc] initWithFrame:frame];
subViewGrid.tag = 12; // use tag to get correct sub-view
subViewGrid.backgroundColor = [UIColor grayColor];
subViewGrid.alpha = 1.0; // make it opaque
[self.schedScrollView addSubview:subViewGrid];
// create a sub-view to hold the appointment DATA
frame = CGRectMake(110,48,670,750);
subViewData = [[UIView alloc] initWithFrame:frame];
subViewData.tag = 22; // use tag to get correct sub-view
subViewData.backgroundColor = [UIColor redColor];
subViewData.alpha = 0.2; // make it sort of transparent
[self.schedScrollView addSubview:subViewData];
[self.subViewGrid setNeedsDisplay]; // **** UPDATED ****
}
Here is the .h file contents for the UIViewController:
#interface CalendarViewController : UIViewController {
UIView *subViewGrid;
UIView *subViewData;
}
#property (strong, nonatomic) IBOutlet UIScrollView *schedScrollView;
- (void) calendarTapNotification:(NSNotification *) notification;
-(NSDate *)beginningOfDay:(NSDate *)date;
-(NSDate *)endOfDay:(NSDate *)date;
#end
In my drawRect method, I have some code that is supposed to draw a "grid" on the subViewGrid. The problem is drawRect never gets called.`
I have read the UIView Programmer's Guide and looked in SO and did a Google search, but found nothing that addresses the issue, which is: why won't [self.subViewGrid setNeedsDisplay] call drawRect from where I have it placed?
Your view controller needs to call setNeedsDisplay for the view it controls, not for itself. So, you want
[self.subViewGrid setNeedsDisplay]
This is just an error in your reading the documentation. Understanding the documentation is critical for objective-C programming so I'll try to help you get a grasp of it.
If you look at the documentation for setNeedsDisplay you will see that it is either a CALayer or UIView class method. If you then look at inheritance, you will see that UIView is UIResponder:NSObject and CALayer is NSObject. None of these inherit from UIViewController which is why you are getting the error. You need to call [self.subViewGrid setNeedsDisplay]

Navigation Bar on top when rotating

I have UIViewController (for example, loginVC) and I'm trying to add it's view on top of all views.
I tried to add this view to AppDelegate
[[AppDelegate sharedDelegate].window addSubview:loginVC.view];
But in this case autorotation doesn't work, so I tried to add this view to NavigationController's view. NavigationController is rootViewController:
[[AppDelegate sharedDelegate].navigationController.view addSubview:loginVC.view];
It looks good and autorotating, but it has strange behavior when rotating.
After beginning of rotation, navigation bar is showing on top of loginVC.view and at the end of rotation is going behind this view, like it shown on screenshots (I've set red background to make it more visible, background is transparent, to see all stuff behind this view):
What I've tried:
I found this somewhere on stackoverflow: disable UIView animations before rotating and enable them after rotating - doesn't look good, because rotating occurs without animation (it's a bit obvious)
tried to make navigationBar hidden before rotation and make it visible after rotation, but in this case navigationBar bringing on top of loginVC.view
Next thing I gonna do - add this view on AppDelegate's window and handle rotation manually, but maybe there is some better way to do this?
UPD:
screenshots:
You can see issue on second screenshot: navigation bar is on top
add your viewController in uinavigationcontroller and push uinavigationcontroller then always navigation bar is visible.
My friend helped me with this problem
Here is the solution:
In AppDelegate I've created UIWindow property:
//AppDelegate.h
#property (nonatomic, strong) UIWindow *loginWindow;
Initialized it when application starts
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
....
self.loginWindow = [[UIWindow alloc] init];
self.loginWindow.windowLevel = UIWindowLevelStatusBar;
self.loginWindow.frame = [[UIScreen mainScreen] bounds];
self.loginWindow.backgroundColor = [UIColor clearColor];
....
return YES;
}
And then, in loginVC:
#interface loginVC ()
#property (nonatomic, weak) UIWindow *loginWindow;
#end
#implementation
....
- (void)show {
// setting up loginVC view
if (!self.loginWindow) {
self.loginWindow = [[AppDelegate sharedDelegate] loginWindow];
}
if (![self.loginWindow.rootViewController isEqual:self]) {
[self.loginWindow setRootViewController:self];
}
self.loginWindow.hidden = NO;
//UPD:
//[self.loginWindow makeKeyAndVisible];
//UPD2:
[self.loginWindow makeKeyWindow];
}
- (void)hide {
// hiding view and stuff
[[[AppDelegate sharedDelegate] loginWindow] setHidden:YES];
//UPD:
//[[[AppDelegate sharedDelegate] window] makeKeyAndVisible];
//UPD2:
[[[AppDelegate sharedDelegate] window] makeKeyWindow];
}
#end
UPD:
No need to use makeKeyAndVisible method of UIWindow, second window will be always on top of first one.
UPD2:
Again updating my answer, maybe it will be useful for somebody.
Without makeKeyAndVisible I couldn't use UITestFields so I uncommented that code and faced another problem:
I have UIViewController, create an instance of another UIViewController inside this controller and call [self presentViewController:...]. In presented UIViewController I'm creating loginVC, but when I call
[[[AppDelegate sharedDelegate] window] makeKeyAndVisible];
presented viewController disappears, but first view controller still has this controller as presentedViewController, so I can't present other view controllers.
My solution was change makeKeyAndVisible on makeKeyWindow.

UIPageViewControllerSpineLocation Delegate Method Not Firing

Major head-scratcher all day on this one :-(
I have an instance of a UIPageViewController that does not appear to be firing the delegate method:
-(UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
I have tried various methods of displaying the UIPageViewController and have settled on a programatic approach (as opposed to a Storyboard one) that appears to be working correctly, with one exception... when rotating the iPad to landscape the spine does not appear mid-point as expected. I simply cannot find out why the delegate method does not get called.
Code Explanation (simplified for example)
Consider three classes as follows:
RootViewController - loaded when the app starts
PageViewController - loaded by RootViewController upon user initiation
PageContentViewController - loaded by PageViewController when pages are needed
Fairly self-explanatory. The RootViewController is loaded by the app upon launch. When the user taps an image within this view controller's view (think magazine cover opening a magazine) it launches the PageViewController as follows:
PageViewController *pvc = [[PageViewController alloc] initWithNibName:#"PageView"
bundle:[NSBundle mainBundle]];
pvc.view.frame = self.view.bounds;
[self.view addSubview:pvc.view];
In the actual app there is animation etc to make the transition all nice, but essentially the PageViewController's view is loaded and takes fullscreen.
PageViewController
This is the workhorse (only relevant methods shown). I have tried various examples from the infinite world of Google and written directly from the Apple docs...
#interface PageViewController : UIViewController <UIPageViewControllerDelegate, UIPageViewControllerDataSource>
#property (nonatomic, strong) UIPageViewController *pageViewController;
#property (nonatomic, strong) NSMutableArray *modelArray;
#end
#implementation TXCategoryController
-(void)viewDidLoad
{
[super viewDidLoad];
// Simple model for demo
self.modelArray = [NSMutableArray alloc] init];
for (int i=1; i<=20; i++)
[self.modelArray addObject:[NSString stringWithFormat:#"Page: %d", i]];
self.pageViewController = [[UIPageViewController alloc]
initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
self.pageViewController.delegate = self;
self.pageViewController.dataSource = self;
PageContentViewController *startupVC = [[PageContentViewController alloc] initWithNibName:#"PageContent" bundle:nil];
startupVC.pageLabel = [self.modelArray objectAtIndex:0];
[self.pageViewController setViewControllers:[NSArray arrayWithObject:startupVC]
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:nil];
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];
self.pageViewController.view.frame = self.view.bounds;
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController
{
// Relevant code to add another view...
}
-(UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController
{
// Relevant code to add another view...
}
-(UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
// Setting a break point in here - never gets called
if (UIInterfaceOrientationIsPortrait(orientation))
{
// Relevant code to create view...
return UIPageViewControllerSpineLocationMin;
}
// Relevant code to create 2 views for side-by-side display and
// set those views using self.pageViewController setViewControllers:
return UIPageViewControllerSpineLocationMid
}
#end
This all works perfectly well as I mentioned earlier. The PageViewController's view gets shown. I can swipe pages left and right in both portrait and landscape and the respective page number appears. However, I don't ever see two pages side-by-side in landscape view. Setting a breakpoint in the spineLocationForInterfaceOrientation delegate method never gets called.
This is such a head-scratcher I have burned out of ideas on how to debug/solve the problem. It almost behaves like the UIPageViewController isn't responding to the orientation changes of the device and therefore isn't firing off the delegate method. However, the view gets resized correctly (but that could be just the UIView autoresizing masks handling that change).
If I create a brand new project with just this code (and appropriate XIb's etc) it works perfectly fine. So something somewhere in my actual project is causing this. I have no idea where to continue looking.
As usual, any and all help would be very much appreciated.
Side Note
I wanted to add the tag 'uipageviewcontrollerspinelocation' but couldn't because it was too long and I didn't have enough reputation (1500 required). I think this is a devious ploy on Apple's part to avoid certain tags in Stackoverflow... ;-)
Finally found the problem. It was something of a red herring in its symptoms, but related just the same.
Putting a break point in the shouldAutorotateToInterfaceOrientation: method was a natural test to see if the UIViewController was even getting a rotation notification. It wasn't which led me to Apple's technical Q&A on the issue: http://developer.apple.com/library/ios/#qa/qa1688/_index.html
The most relevant point in there was:
The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller.
Unfortunately, Apple, in its traditional documentation style, doesn't provide an answer, merely confirmation of the problem. But an answer on Stack Overflow yielded the next clue:
Animate change of view controllers without using navigation controller stack, subviews or modal controllers?
Although my RootViewController was loading the PageViewController, I was doing it as a subview to the main view. This meant I had two UIViewController's in which only the parent would respond to changes.
The solution to get the PageViewController to listen to the orientation changes (thus triggering the associated spine delegate method) was to remove addSubview: and instead present the view controller from RootViewController:
[self presentViewController:pac animated:YES completion:NULL];
Once that was done, the orientation changes were being picked up and the PageViewController was firing the delegate method for spine position. Only one minor detail to consider. If the view was launched in landscape, the view was still displaying portrait until rotated to portrait and back to landscape.
That was easily tweaked by editing viewDidLoad as follows:
PageContentViewController *page1 = [[PageContentViewController alloc] initWithNibName:#"PageContent" bundle:nil];
NSDictionary *pageViewOptions = nil;
NSMutableArray *pagesArray = [NSMutableArray array];
if (IS_IPAD && UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
pageViewOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:UIPageViewControllerSpineLocationMid]
forKey:UIPageViewControllerOptionSpineLocationKey];
PageContentViewController *page2 = [[PageContentViewController alloc] initWithNibName:#"PageContent" bundle:nil];
[pagesArray addObject:page1];
[pagesArray addObject:page2];
}
else
{
[pagesArray addObject:page1];
}
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:pageViewOptions];
self.pageViewController.delegate = self;
[self.pageViewController setViewControllers:pagesArray
direction:UIPageViewControllerNavigationDirectionForward
animated:NO
completion:NULL];
Job done and problem solved.

UIScrollView ScrollRectToVisible - not working with animate = yes

I have a UIScrollView which contains a button.
When the button is pressed, I would like to scroll to the bottom of the view using scrollRectToVisible.
eg:
CGRect r = CGRectMake(0, myUIScrollView.contentSize.height - 1, 1, 1);
[myUIScrollView scrollRectToVisible:r animated:YES];
If I set animated to NO, everything works as expected,
but if I set it to YES, I see really weird behaviour:
basically, nothing happens.
if I tap the button repeatedly, it may scroll a couple pixels,
or may scroll all the way.
but if I scroll the view manually with a finger before pressing the button,
it has a chance of scrolling to the bottom as expected, but it's not a sure thing.
I've printed _geScroll_Settings.contentSize, and it's as-expected.
I've also tried to delay the call to scrollRectToVisible by starting a timer, but the results are pretty much the same.
The scrollView is fairly vanilla.
I'm creating it in interface builder.
I am dynamically adding the scrollView's content at startup, and adjusting it's contentSize appropriately, but all that seems to be working fine.
Any thoughts?
My bet is that scrollRectToVisible is crapping out because the visible area is not valid (1x1), or the y offset is just outside the bounds, have you tried setting it with the size of the visible area of the scrollView instead?
CGRect rectBottom = CGRectZero;
rectBottom.size = myUIScrollView.frame.size;
rectBottom.origin.y = myUIScrollView.contentSize.height - rectBottom.size.height;
rectBottom.origin.x = 0;
[myUIScrollView scrollRectToVisible:rectBottom animated:YES];
Sorry I can't help you out more, but I'm not on my Mac right now, so I can't run a test. The code above would create a CGRect of the exact size of what fits inside the scrollView visible portion, and the offset would be the last visible portion in it.
I encountered a similar problem, including the "If I set animated to NO, everything works as expected" part.
It turned out that on iOS 6 the UITextView auto scrolls its nearest parent UIScrollView to make the cursor visible when it becomes first responder. On iOS 7 there is no such behavior. The UIScrollView seems to get confused by two calls to to scrollRectToVisible at about the same time.
On iOS 6 my explicit call to scrollRectToVisible is ignored most of the time. It will only scroll to make the first line of the UITextView visible (the auto scroll) and not the whole thing as it does on iOS 7.
To test it, make a new single view app in Xcode 5, set its deployment target to 6.0 and use the code below for the ViewController.m. Run it in the iOS 6.1 simulator, scroll to make the UITextView hidden and tap anywhere on the screen. You might have to retry it a few times, but in most cases it will only make the first line visible. If you re-enable the WORKAROUD define the UITextView gets embedded in its own UIScrollView and the call to scrollRectToVisible works as expected.
#import "ViewController.h"
//#define WORKAROUND
#interface ViewController ()
#property (nonatomic, strong) UIScrollView *scrollView;
#property (nonatomic, strong) UITextView *textView;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTap)]];
self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 240)];
self.scrollView.contentSize = CGSizeMake(320, 400);
self.scrollView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.scrollView];
#ifdef WORKAROUND
UIScrollView* dummyScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(20, 280, 280, 100)];
self.textView = [[UITextView alloc] initWithFrame:dummyScrollView.bounds];
[dummyScrollView addSubview:self.textView];
[self.scrollView addSubview:dummyScrollView];
#else
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 280, 280, 100)];
[self.scrollView addSubview:self.textView];
#endif
self.textView.backgroundColor = [UIColor grayColor];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewTap
{
if (self.textView.isFirstResponder) {
[self.textView resignFirstResponder];
}
else {
[self.textView becomeFirstResponder];
}
}
- (void)keyboardWasShown:(NSNotification*)aNotification
{
#ifdef WORKAROUND
[self.scrollView scrollRectToVisible:CGRectInset(self.textView.superview.frame, 0, -10) animated:YES];
#else
[self.scrollView scrollRectToVisible:CGRectInset(self.textView.frame, 0, -10) animated:YES];
#endif
}
#end