How to position views with CCUIViewWrapper - ios

I am using the code from http://www.cocos2d-iphone.org/forum/topic/6889 to add a UIView to the screen in a Cocos2d game. It works great in non-retina resolution (everything is positioned correctly), but in retina resolution the UIView is placed in a different location. The code I am using to add the view to the game is basically the same as the code from the website:
UIView *myView = [[[UIView alloc] init] autorelease];
myView.backgroundColor = [UIColor redColor];
CCUIViewWrapper *wrapper = [CCUIViewWrapper wrapperForUIView:myView];
wrapper.contentSize = CGSizeMake(100, 100);
wrapper.position = ccp(50,50);
[self addChild:wrapper];
The view appears 50px from the bottom and left corner in non retina and 0px from left and 100px up in retina.

The positioning for the wrapper in retina mode is ccp(320,0). No idea why, but it works.
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00) {
wrapper.position = ccp(320,0); //Retina
} else {
wrapper.position = ccp(160,240); //Normal
}

The CCUIViewWrapper (at least in the form from the forum thread) does not use CC_CONTENT_SCALE_FACTOR(). That means it's not compatible with Retina displays.
You may be able to get around this by supplying properly scaled size and position, this may or may not work:
wrapper.contentSize = CGSizeMake(100 * CC_CONTENT_SCALE_FACTOR(),
100 * CC_CONTENT_SCALE_FACTOR());
wrapper.position = ccp(50 * CC_CONTENT_SCALE_FACTOR(),
50 * CC_CONTENT_SCALE_FACTOR());

Related

Objective - C, what does [UIScreen mainScreen].bounds.size.width actually give and what does initWithSize: actually require?

I am writing a GUI, with a main menu, a second screen and a back button to the main menu. From the initial main menu I use the following lines of code:
midScreenX = [UIScreen mainScreen].bounds.size.width/2;
midScreenY = [UIScreen mainScreen].bounds.size.height/2;
WarScene *battle = [[WarScene alloc] initWithSize: CGSizeMake(midScreenX*2, midScreenY*2)];
SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
SKView * skView = (SKView *)self.view;
UIView *viewToRemove = [self.view viewWithTag:101];
[viewToRemove removeFromSuperview];
[skView presentScene:battle transition:reveal];
This works... I think. I open up a new scene, my second scene is the correct size and at least fills the screen. There is a node in that scene which is too big for the screen, and I am working on changing that, but I don't think that that would actually effect the UIScreen's bounds.
The problem arises when I return to the main menu with the following code:
midScreenX = [UIScreen mainScreen].bounds.size.width/2;
midScreenY = [UIScreen mainScreen].bounds.size.height/2;
GameScene *map = [[GameScene alloc] initWithSize: CGSizeMake(midScreenX*2 ,midScreenY*2)];
SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
SKView * skView = (SKView *)self.view;
UIView *viewToRemove = [self.view viewWithTag:3];
[viewToRemove removeFromSuperview];
[skView presentScene:map transition:reveal];
As far as I can work out, the values being passed through should be exactly the same as the values initially sent for [UIScreen mainScreen].bounds.size and yet the scene which is initialised is far too big.
Is there anything that I could be doing which might affect [UIScreen mainScreen].bounds.size? Or have I misunderstood what init and .bounds actually do?
In terms of what I have already done to try and solve this problem myself, I have looked at examples of how scenes are normally initialised. I see that often values are used in place of .bounds for example :
initWithSize: CGSizeMake(1024,768)
However, wouldn't that mean that on different devices the scene wouldn't be shown properly/fully?
if you are using iOS 6 or iOS 7,
both [UIScreen mainScreen].bounds.size.width and [UIScreen mainScreen].bounds.size.height is same in all orientation..
but in iOS 8 it give one value in landscape and give another value in portrait mode
NSLog(#"width %f",[[UIScreen mainScreen] bounds].size.width); //portrait ios7 or 6 = 320 , landscape ios7 or 6 = 320
NSLog(#"height %f",[[UIScreen mainScreen] bounds].size.height); //portrait ios7 or 6 = 568 , landscape ios7 or 6 = 568
NSLog(#"width %f",[[UIScreen mainScreen] bounds].size.width); //portrait ios8 = 320 , landscape ios8 = 568
NSLog(#"height %f",[[UIScreen mainScreen] bounds].size.height); //portrait ios8 = 568 , landscape ios8 = 320
so we can check conditions like this,
CGFloat midScreenX,midScreenY;
if (UIDeviceOrientationIsLandscape((UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation]))
{
//landscape mode
midScreenX = ([[UIScreen mainScreen]bounds].size.width>[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
midScreenY = ([[UIScreen mainScreen]bounds].size.width<[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
}
else
{
//portrait mode
midScreenX = [[UIScreen mainScreen]bounds].size.width/2;
midScreenY = [[UIScreen mainScreen]bounds].size.height/2;
}
I hope you warScene and gameScene are subclass of SKScene. The method initWithSize returns, A newly initialized scene object. and parameter 'size' is The size of the scene in points.
For more information refer https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKScene_Ref/index.html#//apple_ref/occ/instm/SKScene/initWithSize:

UIImagePickerController Camera view size issue

I'm building an app using the UIImagePickerController and a custom Overlay. What is does is comparing two images (before image and after image). I am using a custom overlay with the before image when taking the after photo(please see the image attached).
iPhone 5 - ios7
iPhone 4 - iOS7 (When taking the image)
iPhone 4 - iOS 7 (After taking the photo)
See the size difference between iPhone 4 and iPhone 5 camera view.
Application works fine with iPhone 5 screen size(Both ios 6 and ios7). But iPhone 4/4s screen size, it works fine ONLY with iOS6. The issue is with iphone 4/4s(ios7 ONLY), Camera view takes full screen.
That means, you can notice
iPhone 5 camera view size ~ 320*427 (iOS 6 and iOS 7)
iPhone 4 camera view size ~ 320*427 (iOS 6)
BUT
iPhone 4 camera view size ~ 320*480 (iOS 7).
After the image is taken, it fitted to the actual size of 320*427. Because of this issue, I cannot align before image with camera view on iPhone 4 iOS7 (because its screeches to 320*480).
Does anyone faces this strange issue. I tried almost everything, but NO luck. Any ideas please???
This is my piece code for loading the camera view with custom before photo overlay.
- (void)loadCameraWithImage
{
if (!isLoadedOnce)
{
isLoadedOnce = YES;
UIImagePickerController *cameraView = [[UIImagePickerController alloc] init];
cameraView.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraView.wantsFullScreenLayout = NO;
if ([self respondsToSelector:#selector(setEdgesForExtendedLayout:)]) {
[self setEdgesForExtendedLayout:UIRectEdgeNone];
}
// crop before image
UIImage *imgTmpCropped = [self imageByCropping:imgBefore toRect:CGRectMake(0, 0, imgBefore.size.width/2, imgBefore.size.height)];
UIImage *overleyImage = [[UIImage alloc] initWithCGImage: imgTmpCropped.CGImage
scale: [UIScreen mainScreen].scale
orientation: UIImageOrientationDownMirrored];
UIImageView *crosshairView;
UIImageView *beforeView;
CGFloat screenHieght = [UIScreen mainScreen].bounds.size.height;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
//overleyImage = [UIImage imageNamed:#"overlay_ipad.png"];
crosshairView = [[UIImageView alloc] initWithImage:overleyImage];
crosshairView.frame = CGRectMake(0, 0, 768, 1024);
[crosshairView setUserInteractionEnabled:YES];
crosshairView.backgroundColor = [UIColor clearColor];
beforeView = [[UIImageView alloc] initWithImage:overleyImage];
beforeView.frame = CGRectMake(0, 0, 384, 1024);
beforeView.alpha = 0.5;
beforeView.contentMode = UIViewContentModeScaleAspectFill;
}
else {
//overleyImage = [UIImage imageNamed:#"overleyImageAfter.png"];
crosshairView = [[UIImageView alloc] init];
beforeView = [[UIImageView alloc] initWithImage:overleyImage];
if(screenHieght>500){
crosshairView.frame = CGRectMake(0, 60, 320, 480);
beforeView.frame = CGRectMake(0, 70, 160, 427);
}
else{
if([[[UIDevice currentDevice] systemVersion] floatValue] <7.0){
crosshairView.frame = CGRectMake(0, 0, 320, 480);
beforeView.frame = CGRectMake(0, 0, 160, 427);
}
else{
crosshairView.frame = CGRectMake(0, 0, 320, 480);
beforeView.frame = CGRectMake(0, 0, 160, 480);
}
}
[crosshairView setUserInteractionEnabled:YES];
crosshairView.backgroundColor = [UIColor clearColor];
beforeView.alpha = 0.5;
beforeView.contentMode = UIViewContentModeScaleToFill;
}
//[crosshairView addSubview:beforeView];
//set our custom overlay view
cameraView.cameraOverlayView = beforeView;
cameraView.delegate = (id)self;
cameraView.showsCameraControls = YES;
cameraView.navigationBarHidden = YES;
cameraView.toolbarHidden = YES;
[cameraView setHidesBottomBarWhenPushed:YES];
[self.view.window.rootViewController presentViewController:cameraView animated:YES completion:nil];
isLoadedOnce = NO;
}
}
TL;DR
Camera's preview has the same aspect ratio in every device (4:3), screens don't. Asume the preview will have that specific aspect ratio and that it will be placed in a specific position on the screen. Draw your overlay inside that area.
Longer:
We faced the same issue. (Our use case is taking pictures of credit cards with an overlay with the same size as a card). The main problem is that the camera preview's proportions are always the same (4:3) in every device but different phones have different screen proportions (iPhone 4s vs iPhone 5, for example) so the preview's need to be fitted differently and that makes putting an overlay and cropping that very difficult.
Our solution was (the code is somewhat messy and hacky, sorry):
// Adjust camera preview to be a little bit more centered instead of adjusted to the top
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0;
float imageHeight = screenSize.width * cameraAspectRatio;
float verticalAdjustment;
if (screenSize.height - imageHeight <= 54.0f) {
verticalAdjustment = 0;
} else {
verticalAdjustment = (screenSize.height - imageHeight) / 2.0f;
verticalAdjustment /= 2.0f; // A little bit upper than centered
}
CGAffineTransform transform = self.cameraController.cameraViewTransform;
transform.ty += verticalAdjustment;
self.cameraController.cameraViewTransform = transform;
CGRect previewFrame = CGRectMake(0, verticalAdjustment, screenSize.width, imageHeight);
CardPhotoView *overlayView = [[CardPhotoView alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, screenSize.height) widthPercentageOfCamera:self.widthPercentageOfCamera previewFrame:previewFrame];
self.overlayView = overlayView;
self.overlayView.delegate = self;
self.overlayView.useViewport = YES;
[self.overlayView setCameraReady:NO];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cameraIsReady:) name:AVCaptureSessionDidStartRunningNotification object:nil];
self.cameraController.showsCameraControls = NO;
self.cameraController.navigationBarHidden = YES;
self.cameraController.toolbarHidden = YES;
self.cameraController.cameraOverlayView = self.overlayView;
[self presentViewController:self.cameraController animated:NO completion:nil];
Explanation:
self.cameraController is a UIImagePickerController. CardPhotoView is a view subclass that draws the overlay, it takes the preview frame to know exactly where the preview will be positioned (some devices will have black bars on top and bottom, some won't). It also takes a width percentage to add a little padding to the cropping window.
Also, we have hidden all default camera controls and we have implemented some buttons that will do the work for us. Those buttons are added in the CardPhotoView class and they are drawn taking into account where the preview frame is.

iOS iPhone Application running iOS7 Retina graphics for iPad2 and iPad Mini

I've noticed that the iPhone applications running on non-retina devices (iPad 2 and iPad Mini) are now by default rendered at iPhone Retina Graphics (2x) (If the Application has the retina assets).
Devices currently running iPhone Applications at Retina Graphics without a retina screen:
iPad 2
iPad Mini
There is now no Zoom option for non-retina devices running an iPhone application with retina graphics in the payload.
This is great however I've been trying to get my Openframeworks iOS environment to work with with the new retina window and it is still rendering a non-retina OpenGL window (as the device itself is not a high dpi 2x scale).
Environments:
openFrameworks 0.8 https://github.com/openframeworks/openFrameworks
Xcode 5.0.1
Target: iOS7
Current main.mm
ofAppiOSWindow * window = new ofAppiOSWindow();
NSInteger glViewW = [UIScreen mainScreen].bounds.size.height;
NSInteger glViewH = [UIScreen mainScreen].bounds.size.width;
// glViewW returns 768
// glViewH returns 1024
window->enableRendererES2();
// [UIScreen mainScreen] is used by enableRetina to check for scale dpi.
window->enableRetina();
window->enableDepthBuffer();
ofSetupOpenGL(ofPtr<ofAppBaseWindow>(window), 320, 480, OF_FULLSCREEN);
window->startAppWithDelegate("AppDelegate");
Main ViewController to run open (GameViewController.mm)
- (BOOL)createGLView {
if(self.glView != nil) {
return NO;
}
app = new GameEngineApp();
app->setDelegate(self);
NSInteger glViewW = [UIScreen mainScreen].bounds.size.height;
NSInteger glViewH = [UIScreen mainScreen].bounds.size.width;
// glViewW returns 320
// glViewH returns 480
CGRect glViewRect = CGRectMake(0, 0, glViewW, glViewH);
self.glView = [[[ofxiOSEAGLView alloc] initWithFrame:glViewRect
andApp:app] autorelease];
self.glView.delegate = self;
self.glView.multipleTouchEnabled = NO;
[appContainer insertSubview:self.glView atIndex:0];
[self.glView layoutSubviews];
[self.glView setup];
[self.glView startAnimation];
return YES;
}
Anyone have any idea? I'm working on a few solutions may have a fix soon.
Okay I found a solution before posting so going to put this up here for reference. :)
So when you create your main.mm, do not enable retina straight away. You need to wait until you have started the AppDelegate and let the native iOS core functions kick in.
So revised Main.mm:
#include "ofMain.h"
#include "ofAppiOSWindow.h"
int main() {
ofAppiOSWindow * window = new ofAppiOSWindow();
window->enableRendererES2();
//-------------------------------------------------------------------------
// --Disabled:-- window->enableRetina(); // delete / comment this line out here
//-------------------------------------------------------------------------
window->enableDepthBuffer();
// the below numbers will not effect the window size as this is done later
ofSetupOpenGL(ofPtr<ofAppBaseWindow>(window), 320,480, OF_FULLSCREEN);
window->startAppWithDelegate("AppDelegate");
}
Revised GameViewController.mm (where I am instantiating the openFrameworks glView):
- (BOOL)createGLView {
if(self.glView != nil) {
return NO;
}
app = new GameEngineApp();
app->setDelegate(self);
NSInteger glViewW = [UIScreen mainScreen].bounds.size.height;
NSInteger glViewH = [UIScreen mainScreen].bounds.size.width;
CGRect glViewRect = CGRectMake(0, 0, glViewW, glViewH);
//-------------------------------------------------------------------------
ofAppiOSWindow::getInstance()->enableRetina(); // <-- Enable retina here
//-------------------------------------------------------------------------
self.glView = [[[ofxiOSEAGLView alloc] initWithFrame:glViewRect
andApp:app] autorelease];
self.glView.delegate = self;
self.glView.multipleTouchEnabled = NO;
[appContainer insertSubview:self.glView atIndex:0];
[self.glView layoutSubviews];
[self.glView setup];
[self.glView startAnimation];
return YES;
}

Round corner full bottom screen for portrait & landscape mode?

I want to add rounded corners image on my UIView, so I made ​​two of my images 12x12px rounded corners.
I want to know how best to add my view taking into account that he must align automatically in portrait and landscape mode in the bottom of the total screen!
This is what I did now, but that does not work:
CGSize result = [[UIScreen mainScreen] bounds].size;
self.brcLeft = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, result.height-12.0, 12.0, 12.0)];
self.brcLeft.image = [UIImage imageNamed:#"brc-left"];
[self.view addSubview:brcLeft];
self.brcRight = [[UIImageView alloc] initWithFrame:CGRectMake(result.width-12.0, result.height-12, 12.0, 12.0)];
self.brcRight.image = [UIImage imageNamed:#"brc-right"];
[self.view addSubview:brcRight];
For setting your views to both orientation at the bottom of the screen do this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
CGRect screenFrame = [[UIScreen mainScreen] bounds];
[self.brcLeft setFrame:CGRectMake(0.0, screenFrame.size.height - self.brcLeft.frame.size.height , 12.0, 12.0)];
[self.brcRight setFrame:CGRectMake(result.width-12.0, screenFrame.size.height - self.brcRight.frame.size.height , 12.0, 12.0)];
return YES;
}
and for rounded Corners:
#import <QuartzCore/QuartzCore.h>
write this in your viewDidLoad
self.brcLeft.layer.cornerRadius = 2;
self.brcLeft.layer.masksToBounds = YES;
self.brcRight.layer.cornerRadius = 2;
self.brcRight.layer.masksToBounds = YES;

UIImageView not centered after rotation

I manually add an UIImageView to my UIView and center it, this works fine, but after rotating the device, the UIImageView isn't centered anymore (it's moved to the lower left). How can I fix this?
logoView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"wi-fi-sticker.png"]];
logoView.center = self.view.center;
[self.view addSubview:logoView];
Regards,
Sascha
I was able to center mine correctly every time using something like this
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration:{
CGRect screen = [[UIScreen mainScreen] bounds];
float pos_y, pos_x;
pos_y = UIDeviceOrientationIsLandscape(toInterfaceOrientation) ? screen.size.width/2 : screen.size.height/2;
pos_x = UIDeviceOrientationIsLandscape(toInterfaceOrientation) ? screen.size.height/2 : screen.size.width/2;
myImageView.center = CGPointMake(pos_x, pos_y);
}

Resources