I am trying to mirror what's on my iPhone to an external display but I can't remove the underscan. All my searches for an answer lead back to "overscanCompensation". Since this is a property of UIScreen, I'm not sure where to add it if I'm not explicitly creating a new UIScreen as mirroring is now automatic.
Auto-mirroring through Lightning HDMI adapter screenshot:
http://blog.axelgimenez.net/dp7-capture-underscan-issue-1.jpg
The other option is to create a UIScreen when a new display is detected. Please see the code below and note that I did use "overscanCompensation = 3". Unfortunately, it doesn't work for me. I've tried all the other overscanCompensation options with no luck.
- (void)checkForExistingScreenAndInitializeIfPresent
{
if ([[UIScreen screens] count] > 1)
{
// Get the screen object that represents the external display.
UIScreen *secondScreen = [[UIScreen screens] objectAtIndex:1];
secondScreen.overscanCompensation = 3;
// Get the screen's bounds so that you can create a window of the correct size.
UIScreenMode *screenMode = [[secondScreen availableModes] lastObject];
CGRect screenBounds = (CGRect){.size = screenMode.size};
self.secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
self.secondWindow.screen = secondScreen;
// Set up initial content to display...
self.secondWindow.backgroundColor = [UIColor redColor];
// Show the window.
self.secondWindow.hidden = NO;
}
}
Here's the screenshot of the display that the code above creates:
http://blog.axelgimenez.net/dp7-capture-underscan-issue-2.jpg
Same issue of underscan. Any help is greatly appreciated.
FYI - Using the Lightning to HDMI adapter, I connected my iPhone 5 to a SmallHD dp7 monitor. The monitor lets me take screen captures. The underscan also appears when I plug into my TV.
Related
I am trying to connect apple tv through airplay, but the issue is some time if i connect any other external device like bluetooth or some other device it shows like device connected in window. So i want to identify which device is connected i have to enable only when apple tv is connected.
How can i identify whether it is apple tv or some other device?
This how i create airplay custom button
for (UIButton *button in volumeView.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
self.airplayButton = (UIButton*)button;
button.frame = CGRectMake(0, 0, 30, 23);
button.backgroundColor = [UIColor clearColor];
[self.airplayButton addObserver:self forKeyPath:#"alpha" options:NSKeyValueObservingOptionNew context:nil];
}
}
So the alpha always changes for button even some other devices gets connected.
I've had a look into this before, there's no easily provided way of determining whether the attached device is an Apple TV, there is a Airplay Picker which does this but the code/functions behind it don't seem to be available.
The best you can do it monitor for additional screens being added/removed and then showing your external content only when the screen has the capabilities to do what you need.
I have read somewhere previously that you can get the capabilities of an airplay device and use this information to detect an Apple TV but unfortunately I cannot find it at the moment. If I do find it I'll add a comment.
For now, your best option would be to use the concepts described in this guide
The code provided is in objective-c but its very easily converted to swift, here is the main part you should be looking at
- (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...
// Show the window.
self.secondWindow.hidden = NO;
}
}
Like I said you can code this so that it checks the device supports certain resolutions so you can rule out devices that wont support your UI
Some additional resources: https://developer.apple.com/airplay/
I want to place content on an external screen (for now a MacBook Pro using Air Server) in full screen, with a screen on a tablet.
I am using an example from https://github.com/quellish/AirPlayStoryboards - which is great. However, I am finding that neither screen is displaying the full screen because the UIScreen's bounds are coming back too small -- the iPad displays a little smaller (letterboxed) and the iPad screen only displays 1/4 of the screen in the top left (origin)
Any idea why this is? The code:
- (void) application:(UIApplication *)__unused application didConnectScreen:(UIScreen *) screen
{
UIStoryboard *storyboard = nil;
UIWindow *screenWindow = nil;
UIViewController *tvViewController = nil;
// Set up external screen
UIScreen *secondaryScreen = [UIScreen screens][1];
UIScreen *primaryScreen = [UIScreen screens][0];
NSLog(#"Screen 1 (iPad): %#", primaryScreen); //print the bounds of the iPad
NSLog(#"Screen 2 (MacBook): %#:", secondaryScreen); //print the bounds and size of the MacBook
UIScreenMode *screenMode = [[secondaryScreen availableModes] lastObject];
CGRect bounds = secondaryScreen.bounds;
// Create new outputWindow
screenWindow = [[UIWindow alloc] initWithFrame:bounds];
screenWindow.screen = secondaryScreen;
screenWindow.screen.currentMode = screenMode;
[screenWindow makeKeyAndVisible];
[screenWindow setScreen:screen];
storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle bundleForClass:[self class]]];
tvViewController = [storyboard instantiateViewControllerWithIdentifier:#"TVViewController"];
[screenWindow setClipsToBounds:YES];
[screenWindow setRootViewController:tvViewController];
[screenWindow setHidden:NO];
// // If you do not retain the window, it will go away and you will see nothing.
[[self windows] addObject:screenWindow];
}
The Log statements return as follows:
Screen 1 (iPad): <UIScreen: 0x1567def0; bounds = {{0, 0}, {480, 320}}; mode = <UIScreenMode: 0x1567dd60; size = 1024.000000 x 768.000000>>
Screen 2 (MacBook): <UIScreen: 0x15680280; bounds = {{0, 0}, {640, 400}}; mode = <UIScreenMode: 0x156804a0; size = 1280.000000 x 800.000000>>:
Does anyone know how I may fix this issue?
You can get the screen size like this:
UIScreen *secondaryScreen = [UIScreen screens][1];
UIScreenMode *secondaryScreenMode = [[secondaryScreen availableModes] objectAtIndex: 0];
CGSize sizeSecendaryScreen = secondaryScreenMode.size;
screenWindow = [[UIWindow alloc] initWithFrame:CGRectMake(0,0, sizeSecendaryScreen.width, sizeSecendaryScreen.height)];
Ref: Setting UIScreen's mode / resolution
I figured this out. It was to do with [UIScreen mainScreen].bounds.size becoming orientation-dependent in iOS8. I got the clue from this post:
Is [UIScreen mainScreen].bounds.size becoming orientation-dependent in iOS8?
In my case there was no launch image for perticular resolution for which I want to support.
For example : If you want to support iPhone5 we need to add launch image of the size of iPhone5.
Please check in your Xcode whether you have all required launch images or not.
This may be your solution. In my case it worked for me!
I need to have my banner ads stratched/filled all across the width of the screen at the bottom.
My code is working for the devices with the width equal to either MOPUB_BANNER_SIZE.width or MOPUB_LEADERBOARD_SIZE.width
But on other devices (iPhone 5/6/etc and some iPads) my only option is to center the banner. here is the code:
if(!_mopubBanner){
NSString* bannerID;
const CGSize* bannerSize;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){
bannerID = #"MopubBannerId";
bannerSize = &MOPUB_BANNER_SIZE;
}
else{
bannerID = #"MopubLeaderboardId";
bannerSize = &MOPUB_LEADERBOARD_SIZE;
}
_mopubBanner = [[MPAdView alloc] initWithAdUnitId:bannerID size:*bannerSize];
_mopubBanner.delegate = self;
CGRect BannerFrameRect;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
BannerFrameRect = CGRectMake(([[UIScreen mainScreen] bounds].size.width - MOPUB_BANNER_SIZE.width) / 2,
[[UIScreen mainScreen] bounds].size.height - MOPUB_BANNER_SIZE.height,
MOPUB_BANNER_SIZE.width,
MOPUB_BANNER_SIZE.height);
}
else
{
BannerFrameRect = CGRectMake(([[UIScreen mainScreen] bounds].size.width - MOPUB_LEADERBOARD_SIZE.width) / 2,
[[UIScreen mainScreen] bounds].size.height - MOPUB_LEADERBOARD_SIZE.height,
MOPUB_LEADERBOARD_SIZE.width,
MOPUB_LEADERBOARD_SIZE.height);
}
_mopubBanner.frame = BannerFrameRect;
}
I have tried setting custom sizes for BannerFrameRect but the banner ad just keeps adjusting itself to the top left corner of the new frame. It does not get scaled.
is there any way to resize the ad?
thank you
please take a look at the MoPub's sample code here:
https://github.com/mopub/mopub-ios-sdk/blob/master/MoPubSampleApp/Controllers/MPLeaderboardBannerAdDetailViewController.m
You can use autoresizing in the UIView, and in your case you could simply add the following to your code:
_mopubBanner.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
hope this helps!
You have two viable solutions:
Use autoresizing masks
_mopubBanner.translatesAutoresizingMaskIntoConstraints = YES;
_mopubBanner.autoresizingMask = UIViewAutoresizingFlexibleWidth;
You'll probably need to set height manually as you only want 'horizontal' stretch.
Much better IMO - use Autolayouts. For this I'd recommend PureLayout as it's really clear and useful.
_mopubBanner.translatesAutoresizingMaskIntoConstraints = NO;
[_mopubBanner autoPinEdgesToSuperviewEdgesWithInsets:UIEdgeInsetsZero excludingEdge:ALEdgeTop];
We have UIWindow code that has worked for years to put up a "blocker" screen. We noticed recently that on an iOS 8.3 iPad the blocker is offset 256 pixels when the blocker is displayed in the landscape orientation. There are few oddities:
1) This does not happen on the simulator, only the device
2) If the blocker is shown in portrait it is fine
3) If the blocker is shown in portrait and then rotated to landscape it is fine.
4) The gap is 256 pixels, which is the difference between the width and the height, i.e., 1024 - 768 = 256.
We've recently updated to Xcode 6, so this could be a factor as well...
This problem can be easily replicated by using the default Xcode Master Detail project and making a few minor changes to the "insertNewObject" method as shown here:
UIWindow *blocker;
- (void)insertNewObject:(id)sender {
blocker = [[UIWindow alloc] init];
[blocker setBackgroundColor:[UIColor colorWithRed:.0 green:.0 blue:.0 alpha:.8]];
[blocker makeKeyAndVisible];
CGRect r = CGRectMake(0, 0, 768, 1024);
[blocker setFrame:r];
}
If you run this code on the simulator, and tap the "+" button you get:
which is what we expect.
However, this same exact code, running on our 8.3 iPad device gives us:
Any ideas of why the simulator works and the device doesn't? Suggestions? Other things to try?
[UPDATE] We've only found one device where is this a problem, an iPad 2. We've also discovered that setting the rootViewController on the UIWindow "solves" the problem.
Here is the fix we used:
blocker = [[UIWindow alloc] init];
[blocker setBackgroundColor:[UIColor colorWithRed:.0 green:.0 blue:.0 alpha:.8]];
UIViewController *blockerRoot = [UIViewController new];
blocker.rootViewController = blockerRoot;
CGRect r = [[UIScreen mainScreen] bounds];
[blocker setFrame:r];
[blocker makeKeyAndVisible];
We also were able to remove rotation adjustment code since now the view controller managed it properly for us (at least for iOS 8 and later). Here's the code we now use for that: (called when the screen is rotated)
- (void)adjustForRotation
{
if ([UIUtil iOS8OrLater]){
// iOS 8 handles this correctly, no need for adjustments...
return;
}
UIInterfaceOrientation io = [[UIApplication sharedApplication] statusBarOrientation];
if (UIInterfaceOrientationIsLandscape(io)){
CGRect r = [[UIScreen mainScreen] bounds];
CGFloat x = r.size.height / 2.0;
CGFloat y = r.size.width / 2.0;
self.center = CGPointMake(x, y);
}
return;
}
You are explicitly set the frame of the blocker to the portrait dimensions. It is only being changed when the device is rotated.
Instead, try getting the size from the display to current window when the blocker is being created.
In my iOS app I need to display custom content on external display (using AirPlay) as well as mirroring some screens on TV.
For presenting custom content I use code from Multiple Display Programming Guide for iOS and it works well: while my iPad is in 'mirror' AirPlay mode I'm able to show some stuff on the TV. However, documentation says6
To re-enable mirroring after displaying unique content, simply remove the window you created from the appropriate screen object.
And this part isn't working at all. I just cannot destroy my window that I use to display content on external screen. Here's the code:
- (void) destroySecondWindow{
if (secondWindow){
for( UIView* view in secondWindow.subviews ){
[view removeFromSuperview];
}
secondWindow.backgroundColor = [UIColor clearColor];
secondWindow.hidden = YES;
// Hide and then delete the window.
[secondWindow removeFromSuperview];
secondWindow = nil;
}
}
As far as unique content should be displayed only when one particular view controller is visible, I'm trying to destroy external window like this:
- (void) viewWillDisappear:(BOOL)animated{
[self destroySecondWindow];
}
Here's how I create second window:
- (void) createSecondWindowForScreen:(UIScreen*)screen{
if( screen == nil || secondWindow != nil ){
return;
}
CGRect screenBounds = screen.bounds;
secondWindow = [[UIWindow alloc] initWithFrame:screenBounds];
secondWindow.backgroundColor = [UIColor blueColor];
secondWindow.screen = screen;
[secondWindow setHidden:NO];
}
So the question is: does anybody know how to re-enable screen mirroring after displaying unique content on TV?
Thanks in advance!