5

目前,我为 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

4 回答 4

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;
    }
}
于 2015-06-02T22:24:09.923 回答
1

您只需要设置过扫描补偿:

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

如果您想要完整的代码来测试它,只需将以下代码放在您的某处并AppDelegate.m随时application: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 时需要任何进一步的帮助,请告诉我,但它应该可以正常工作。

于 2015-06-21T15:06:26.417 回答
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;
于 2015-06-21T09:17:50.100 回答
0

这适用于带有 iPad Air 的新旧 Apple TV。第二个窗口在电视上全屏显示,而您的普通 UI 显示在 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

于 2016-03-14T02:59:24.593 回答