AirPlay到Apple TV Fullscreen

时间:2015-06-02 21:06:54

标签: ios airplay apple-tv

目前,我为iPhone / iPad制作的任何应用都可以通过AirPlay镜像到Apple TV。但是,即使在横向模式下,它也只占据屏幕的中央部分,左侧和右侧都是黑色。以Real Racing HD这样的应用程序的方式将它全部转移到AirPlay全部是什么?

编辑:根据建议,我添加了我正在使用的所有代码,而不是告诉secondWindow正常使用相同的根视图控制器,我设置了一个不同颜色的新VC,看看是否有机制设置正确。它们不是,因为它仍然只是正常的镜像,即使告诉它使用不同的VC。

这是AppDelegate.h

#import <UIKit/UIKit.h>
@class MainView;
@class ViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate> {
    UIWindow *window;
    UINavigationController *tabBarController;

}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *tabBarController;
@property (nonatomic, retain) UIWindow *secondWindow;
@end

AppDelegate.m的相关部分

- (void)checkForExistingScreenAndInitializeIfPresent {
    if ([[UIScreen screens] count] > 1) {
        // Get the screen object that represents the external display.
        UIScreen *secondScreen = [[UIScreen screens] objectAtIndex:1];
        // Get the screen's bounds so that you can create a window of the correct size.
        CGRect screenBounds = secondScreen.bounds;

        self.secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
        self.secondWindow.screen = secondScreen;

        // Set up initial content to display...
        NSLog(@"Setting up second screen: %@", secondScreen);
        ViewController *mainView = [[ViewController alloc] init];
        self.secondWindow.rootViewController = mainView;
        [self.secondWindow makeKeyAndVisible];

        // Show the window.
        //        self.secondWindow.hidden = NO;
    }
    NSLog(@"Screen count too low");
}

- (void)setUpScreenConnectionNotificationHandlers {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [center addObserver:self selector:@selector(handleScreenDidConnectNotification:)
                   name:UIScreenDidConnectNotification object:nil];
    [center addObserver:self selector:@selector(handleScreenDidDisconnectNotification:)
                   name:UIScreenDidDisconnectNotification object:nil];
}

- (void)handleScreenDidConnectNotification:(NSNotification*)aNotification {
    UIScreen *newScreen = [aNotification object];
    CGRect screenBounds = newScreen.bounds;

    if (!self.secondWindow) {
        NSLog(@"Initializing secondWindow/screen in notification");
        self.secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
        self.secondWindow.screen = newScreen;

        // Set the initial UI for the window.
        ViewController *mainView = [[ViewController alloc] init];
        self.secondWindow.rootViewController = mainView;
    } else {
        NSLog(@"Second window already initialized.");
    }
}

- (void)handleScreenDidDisconnectNotification:(NSNotification*)aNotification {
    if (self.secondWindow) {
        // Hide and then delete the window.
        self.secondWindow.hidden = YES;
        self.secondWindow = nil;
    }
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window setRootViewController:tabBarController];
    [self setUpScreenConnectionNotificationHandlers];
    [self checkForExistingScreenAndInitializeIfPresent];
return YES;
}

4 个答案:

答案 0 :(得分:3)

  

将其全部播放到AirPlay全部参与......

如果你想直接进入,你可以在这里开始学习iOS世界中的Windows和屏幕:https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/WindowAndScreenGuide/UsingExternalDisplay/UsingExternalDisplay.html

如果您想先了解更广泛的概述,请参阅包含视频和其他教程/文档的聚合页面:

https://developer.apple.com/airplay/

[编辑]这是我的应用程序的代码摘录,我正在设置第二个显示。我从我给你的链接中取了很多这个。注意:“main”表示设备,“remote”表示电视。

注意:此代码不是生产完成的;它仍然没有响应的状态变化。连接到AirPlay接收器并在运行之前打开镜像。

我有这个:

@interface AppDelegate () {
    SFCManagerMainViewController *_mainVC;
    SFCRemoteMonitorViewController *_remoteVC;
}

@end

标题:

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIWindow *secondWindow;

和此:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.

[self setUpScreenConnectionNotificationHandlers];
[self checkForExistingScreenAndInitializeIfPresent];

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_mainVC = [[SFCManagerMainViewController alloc] initWithNibName:nil bundle:nil];
self.window.rootViewController = _mainVC;
[self.window makeKeyAndVisible];
return YES;
}

- (void)checkForExistingScreenAndInitializeIfPresent {
    if ([[UIScreen screens] count] > 1) {
        // Get the screen object that represents the external display.
        UIScreen *secondScreen = [[UIScreen screens] objectAtIndex:1];
        // Get the screen's bounds so that you can create a window of the correct size.
        CGRect screenBounds = secondScreen.bounds;

        self.secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
        self.secondWindow.screen = secondScreen;

        // Set up initial content to display...
        NSLog(@"Setting up second screen: %@", secondScreen);
        _remoteVC = [[SFCRemoteMonitorViewController alloc] initWithNibName:nil bundle:nil];
        self.secondWindow.rootViewController = _remoteVC;
        [self.secondWindow makeKeyAndVisible];

        // Show the window.
        self.secondWindow.hidden = NO;
    }
}

- (void)setUpScreenConnectionNotificationHandlers {
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [center addObserver:self selector:@selector(handleScreenDidConnectNotification:)
                   name:UIScreenDidConnectNotification object:nil];
    [center addObserver:self selector:@selector(handleScreenDidDisconnectNotification:)
                   name:UIScreenDidDisconnectNotification object:nil];
}

- (void)handleScreenDidConnectNotification:(NSNotification*)aNotification {
    UIScreen *newScreen = [aNotification object];
    CGRect screenBounds = newScreen.bounds;

    if (!self.secondWindow) {
        NSLog(@"Initializing secondWindow/screen in notification");
        self.secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
        self.secondWindow.screen = newScreen;

        // Set the initial UI for the window.
        _remoteVC = [[SFCRemoteMonitorViewController alloc] initWithNibName:nil bundle:nil];
        self.secondWindow.rootViewController = _remoteVC;
    } else {
        NSLog(@"Second window already initialized.");
    }
}

- (void)handleScreenDidDisconnectNotification:(NSNotification*)aNotification {
    if (self.secondWindow) {
        // Hide and then delete the window.
        self.secondWindow.hidden = YES;
        self.secondWindow = nil;
    }
}

答案 1 :(得分:1)

您只需设置过扫描补偿:

UIScreen* secondScreen = (...);
secondScreen.overscanCompensation = UIScreenOverscanCompensationInsetApplicationFrame;

如果您需要完整的代码来测试它,只需将以下代码放在AppDelegate.mapplication:didFinishLaunchingWithOptions:电话[self setupAirplay];

的某个位置
-(void)setupAirplay{
    // self.windows is a NSMutableArray property on AppDelegate
    self.windows = [[NSMutableArray alloc] init];

    NSArray* screens = [UIScreen screens];
    for (UIScreen *_screen in screens){
        if (_screen == [UIScreen mainScreen])
            continue;

        NSNotification* notification = [[NSNotification alloc] initWithName:UIScreenDidConnectNotification object:_screen userInfo:nil];
        [self screenDidConnect:notification];
    }

    // Register for notifications
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(screenDidConnect:)
                                                 name:UIScreenDidConnectNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(screenDidDisconnect:)
                                                 name:UIScreenDidDisconnectNotification
                                               object:nil];
}

- (UIWindow *) createWindowForScreen:(UIScreen *)screen {
    UIWindow    *aWindow    = nil;

    // Do we already have a window for this screen?
    for (UIWindow *window in self.windows){
        if (window.screen == screen){
            aWindow = window;
        }
    }
    // Still nil? Create a new one.
    if (aWindow == nil){
        aWindow = [[UIWindow alloc] initWithFrame:[screen bounds]];
        [aWindow setScreen:screen];
        [self.windows addObject:aWindow];
    }

    return aWindow;
}

- (void) screenDidConnect:(NSNotification *) notification {

    UIScreen* screen = [notification object];
    NSLog(@"Screen connected: %.0f x %.0f", screen.bounds.size.width, screen.bounds.size.height);

    // Create a view controller for the new window (you should use a Storyboard / XIB)
    UIViewController* airplay = [[UIViewController alloc] init];
    airplay.view = [[UIView alloc] initWithFrame:screen.bounds];
    [airplay.view setBackgroundColor:[UIColor whiteColor]];

    UILabel* label = [[UILabel alloc] initWithFrame:screen.bounds];
    [label setTextAlignment:NSTextAlignmentCenter];
    [label setFont:[UIFont systemFontOfSize:40.0f]];
    [label setText:@"AirPlay Screen"];

    [airplay.view addSubview:label];

    // Comment this line and you'll get the four black borders:
    screen.overscanCompensation = UIScreenOverscanCompensationInsetApplicationFrame;

    UIWindow* aWindow = [self createWindowForScreen:screen];

    // Add the view controller to the window
    [aWindow setRootViewController:airplay];
    [aWindow setHidden:NO];
}

- (void) screenDidDisconnect:(NSNotification *) notification {

    NSLog(@"Screen disconnected");
    UIScreen* screen = [notification object];

    // Find any window attached to this screen, remove it from our window list
    for (UIWindow *oneWindow in self.windows){
        if (oneWindow.screen == screen){
            NSUInteger windowIndex = [self.windows indexOfObject:oneWindow];
            [self.windows removeObjectAtIndex:windowIndex];
        }
    }
    return;
}

我使用iPad Mini 2进行测试时,我的Apple TV第3代没有获得1080p分辨率,但我将720p扩展到全屏。我不确定这是不是整个AirPlay概念的预期,或者这里的东西不够快,但我希望我能得到1080p。

如果您需要任何有关设置AirPlay的更多帮助,请告诉我,但它应该按原样运行。

答案 2 :(得分:0)

首先,电视本身是否有可能覆盖一些过扫描设置?

您可能希望查看UIScreen的一些API,具体来说是:

@property(nonatomic) UIScreenOverscanCompensation overscanCompensation 
@property(nonatomic,retain) UIScreenMode *currentMode
@property(nonatomic,readonly,copy) NSArray *availableModes

否则另一个选项是禁用镜像并将绘图绘制到与屏幕大小相同的视图中:

//Be sure to check for the screen's existence first :)
UIScreen *secondScreen = [UIScreen screens][1];

//Create a window that is the size of the second screen
self.externalWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, secondScreen.bounds.size.width, secondScreen.bounds.size.height)];

//Set to a view controller that should be displayed
self.externalWindow.rootViewController = [[MyViewController alloc] init]; 

//Move the new window to the second screen
self.externalWindow.screen = secondScreen;
self.externalWindow.hidden = NO;

答案 3 :(得分:0)

这适用于带有iPad Air的新旧Apple TV。 当您的普通用户界面显示在iPad上时,第二个窗口将全屏显示在电视上。

插入AppDelegate.m:

@property UIWindow *secondWindow;

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

  if ([UIScreen screens].count > 1) {
    [self setUpSecondWindowForScreen:[UIScreen screens][1]];
  }

  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
  [center addObserver:self selector:@selector(handleScreenDidConnectNotification:)
                 name:UIScreenDidConnectNotification object:nil];
  [center addObserver:self selector:@selector(handleScreenDidDisconnectNotification:)
                 name:UIScreenDidDisconnectNotification object:nil];

  return YES;
}

- (void)handleScreenDidConnectNotification:(NSNotification*)notification {
  if (!self.secondWindow) {
    [self setUpSecondWindowForScreen:[notification object]];
  }
}

- (void)handleScreenDidDisconnectNotification:(NSNotification*)notification {
  if (self.secondWindow) {
    self.secondWindow = nil;
  }
}

- (void)setUpSecondWindowForScreen:(UIScreen*)screen {
  self.secondWindow = [[UIWindow alloc] init];
  self.secondWindow.screen = screen;
  self.secondWindow.screen.overscanCompensation = UIScreenOverscanCompensationNone;

  UIViewController *viewController = [[UIViewController alloc] init];
  viewController.view.backgroundColor = [UIColor redColor];
  self.secondWindow.rootViewController = viewController;

  [self.secondWindow makeKeyAndVisible];
}

代码启发于:https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/WindowAndScreenGuide/UsingExternalDisplay/UsingExternalDisplay.html