iOS/OpenGL: How to handle a 12288x1024 pixel scene - ios

I'm implementing a landscape mode iPad finger painting app based on Apple's GLPaint example. My drawing canvas is 12x wider than the screen size: 12288 x 768 pixels.
Currently I have placed 12 PaintingView (see above example) instances side by side on a UIScrollView and have modified the example to handle drawing across these instances:
// add PaintingView instance to scrollView (self)
// and to the drawingViews array
for (int drawingIndex = 0; drawingIndex < 12; drawingIndex++) {
PaintingView *drawingView = [[PaintingView alloc]
initWithFrame:CGRectMake(drawingIndex*1024, 0, 1024, 768)];
[self addSubview:drawingView];
[drawingViews addObject:drawingView];
[drawingView release];
}
While it works fine, I have the feeling that this is not the proper way of dealing with my requirements. Being a novice with OpenGL I have tried various approaches, but failed to create a scene large enough and a viewport that scrolls in sync with the UIScrollView.
Any hints/comments are much appreciated.

Related

AutoLayout for CGRect for Universal App

I have a GameViewController.
In this GVC im generating a CGRect like this:
-(void) generateLevel1 {
int j = 0;
for (int i = 0; i < [self.gameModel.cards count]; i++) {
NSInteger value = ((CardModel *)self.gameModel.cards[i]).value;
CGFloat x = (i % _CARDS_PER_ROW) * 120 + (i % _CARDS_PER_ROW) * 40 + 208;
CGFloat y = j * 122 + j * 40 + 324;
CGRect frame = CGRectMake(x, y, 125, 125);
CardView *cv = [[CardView alloc] initWithFrame:frame andPosition:i andValue:value];
if (!((CardModel *)self.gameModel.cards[i]).outOfPlay) {
[self.boardView addSubview:cv];
}
}
}
So i have now my View called boardView, and added a subView called cv.
My Code is written for iPad, and now i want to make an universal App, so i need, that my CGRect is downsized for iPhone 4,5,6,6+.
Whats the best way to do that?
The best would be to reimplement the view with usage of the UICollectionView which then you could define the layout for particular screen bounds.
You can't use Auto Layout (constraints) AND CGRect (frames). Constraints determine origin (x,y) and size (h,w) of a view. Auto Layout uses constraints to manage positioning and sizing frames for you. You can't size or position them yourself, if they are also constrained.
The reason why you should reimplement your code is called 'Adaptive UI'. You want your app to support different devices. Will your existing code work on an Pad running iOS 9 which can show two split-screen apps side-by-side?
If you're trying to figure out your board size, and haven't handled all these edge cases, including new devices or upcoming changes in iOS 9, your app (layout) will break.
If you do yourself a favor and reimplement it the way Apple suggests, your app will support these upcoming changes, and still lay itself out correctly.
Can it be done programmatically? Yes. But Storyboards and Auto Layout are generally easier ways that handle things for you, and you don't need to write most of the code you already wrote.

iOS: understanding frame and views

I am working programmatically an application for iOS based on a ViewController. I am trying to do so programmatically as I want to understand the underlying concepts.
I have created a subclass of UIImageView and initialized this using an image. In the initialization method I added also a second UIImageView as I would like to handle the two differently but be part of the same object. Ultimately I would like to be able to scale the object (and hence the 2 UIImages) according to the device screen resolution (e.g. if resolution is low then I will scale the two images by 50%). I want to do this because I would like to be able to implement a zoom in and zoom out feature as well as supporting multiple resolutions and screen layouts.
Additional information:
The two images have different size (500x500 pixels) and (350x350
pixels).
My questions are:
how do I position the second image exactly in the center of the first? (I used the center property of the main UIImage but I think I got it wrong.. I thought that the center was the exact center of the square but either I am using it incorrectly or there is something I am missing)
are there any negative side effects for using this approach (UIView subclass class containing an additional UIView?) (E.g. Is it going to create confusion when applying transformation algorithms? Does it reduce the randering speed? Or more simply is it a bad design pattern?)
I find it difficult to understand the positioning of the second image. See code snipped below, this is what I use:
CGRect innerButtonFrame = CGRectMake(self.center.x/2, self.center.y/2,innerButtonSelectedImage.size.width,innerButtonSelectedImage.size.height);
Taken from:
-(id) initWithImage:(UIImage *)image
{
if(self = [super initWithImage:image]){
//
self.userInteractionEnabled = true;
// Initialize gesture recognizers
UITapGestureRecognizer *tapInView = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapInImageView:)];
[self addGestureRecognizer:tapInView];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressInView:)];
[self addGestureRecognizer:longPress];
// Initialize labels
..
// Inner circle image
innerButtonView = [[UIImageView alloc] init];
innerButtonSelectedImage = [UIImage imageNamed:#"inner circle.png"];
CGRect innerButtonFrame = CGRectMake(self.center.x/2, self.center.y/2,innerButtonSelectedImage.size.width,innerButtonSelectedImage.size.height);
innerButtonView.frame = innerButtonFrame;
[innerButtonView setImage:innerButtonSelectedImage];
// Add additional ui components to view
[self addSubview:innerButtonView];
..
[self addSubview:descriptionLabel];
}
return self;
}
EDIT: This is how it looks like if I change the positioning code to the following:
CGRect innerButtonFrame = CGRectMake(0, 0,innerButtonSelectedImage.size.width,innerButtonSelectedImage.size.height);
innerButtonView.frame = innerButtonFrame;
I also don't understand why the image is bigger than the screen.. as the blue one should be 500x500 pixel wide and the screen of the iPhone 6 should be 1334 x 750.
How about:
CGRect innerButtonFrame = CGRectMake(0, 0, innerButtonSelectedImage.size.width,innerButtonSelectedImage.size.height);
innerButtonFrame.center = self.center;
If you need 500*500 circle then add the circle half means Replace 500*500 with 250*250 . And small circle replace 350*350 with 175*175 And solve your problem.
I hope your problem will solve..Enjoy
Thanks..

How to overlay two images in ios6 with transparency

I am trying to overlay two images and put text on top in a view that I have. I have this working perfectly in ios7. Here is a screen shot of the results
Right now the gradient is simply an image on top of the other image as seen here in my layout
This works great except for when I test on my phone with ios6. Then everything goes nuts as seen here. *I've actually deleted the gradient layer and ran the app again and the background image remains the same size (about half of what it should be).
As you can see, the background image is only half of what it should be, and the second image is not overlaying. I've been at this for 5 hours and can't seem to find a solution that works.
Here is the code that sets the background image
-(void) SetDetails
{
if(_curInfo)
{
_lblTopName.text = _curInfo.company_name;
if(!_curInfo.img)
{
showActivity(self);
dispatch_queue_t aQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(aQueue1, ^{
_curInfo.img = getImageFromURL([NSString stringWithFormat:#"%#%#", g_serverUrl, _curInfo.imgPath]);
dispatch_async(dispatch_get_main_queue(), ^{
hideActivity();
[_imgCompany setImage:_curInfo.img];
});
});
}
[_imgCompany setImage:_curInfo.img];
/* FIX IMAGE SIZE */
_imgCompany.contentMode=UIViewContentModeScaleAspectFill;
CGRect photoFrame = _imgCompany.frame;
photoFrame.size = CGSizeMake(320, 180);
_imgCompany.frame=photoFrame;
[_imgCompany setClipsToBounds:YES];
_lblDistance.text = [NSString stringWithFormat:#"%.2f miles", _curInfo.distance];
_lblReward.text=_curInfo.reward;
CGFloat scrollViewHeight = 0.0f;
for (UIView* view in scroller.subviews)
{
scrollViewHeight += view.frame.size.height;
}
[scroller setContentSize:(CGSizeMake(320, scrollViewHeight))];
}
}
Any help is greatly appreciated. I'm not opposed to drawing the gradient onto the image either.
Additional Info:
Here is how I have the two image views setup.
You need to unstick the 'opaque' option on your image view, given that it isn't opaque.
As to the other spacing issue, I'd guess it's a mismatch between iOS 7 view controllers always acting as if they had wantsFullScreenLayout set to YES but the default having been NO under iOS 6. The rest of your image is probably underneath your navigation bar. It looks like you're part trying the interface builder and part doing programmatic layout — why did you add the code underneath FIX IMAGE SIZE and what happens if you remove it?

iOS Sprite Kit - SKSpriteNode's .centerRect property not working

I was going through the SpriteKit documentation by Apple and came across a really useful feature that I could use when programming my UI. The problem is I can't get it to work.
Please see this page and scroll down to "Resizing a Sprite" - Apple Docs
I have literally copied the image dimensions and used the same code incase I was doing something wrong. But I always end up with a stretched looking image rather than the correct "end caps" staying the same scale.
I am referring to this code:
SKSpriteNode *button = [SKSpriteNode spriteWithImageNamed:#"stretchable_button.png"];
button.centerRect = CGRectMake(12.0/28.0,12.0/28.0,4.0/28.0,4.0/28.0);
What am I doing wrong? Is there a step I have missed?
EDIT:
Here is the code I have been using. I stripped it of my button class and tried to use it with an SKSPriteNode but still the problem persists. I also changed the image just to make sure it wasnt that. The image im using is a 32x32 at normal size.
SKSpriteNode *button = [SKSpriteNode spriteNodeWithImageNamed:#"Button.png"];
[self addChild:button];
button.position = ccp(200, 200);
button.size = CGSizeMake(128, 64);
button.centerRect = CGRectMake(9/32, 9/32, 14/32, 14/32);
The .centerRect property works as documented if you adjust the sprites .scale property.
Try:
SKTexture *texture = [SKTexture textureWithImageNamed:#"Button.png"];
SKSpriteNode *button = [[SKSpriteNode alloc] initWithTexture:texture];
button.centerRect = CGRectMake(9/32, 9/32, 14/32, 14/32);
[self addChild:button];
button.xScale = 128.0/texture.size.width;
button.yScale = 64.0/texture.size.height;
9/32 is integer division, so the result passed to CGRectMake is zero. Ditto the other three parameters. If you use floating point literals like the example you cite, you might get better results.
Here's a refresh of how exactly this works. By the way, my image size width is 48 pixels and height is 52 pixels, but this doesn't matter at all. Any image can be used:
SKSpriteNode *button = [SKSpriteNode spriteNodeWithImageNamed:#"Button.png"];
//(x, y, width, height). First two values are the four corners of the image that you DON'T want touched/resized (They will just be moved).
//The second two values represent how much of images width & height you want cut out & used as stretching material. Cut out happens from the center of the image.
button.centerRect = CGRectMake(20/button1.frame.size.width, 20/button1.frame.size.height, 5/button1.frame.size.width, 15/button1.frame.size.height);
button.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); //Positions sprite in the middle of the screen.
button.xScale = 4; //Resizes width (This is all I needed).
//button.yScale = 2; //Resizes height (Commented out because I didn't need this. You can uncomment if the button needs to be higher).
[self addChild:button];
Read the section called "Resizing a Sprite" in this document: https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Sprites/Sprites.html#//apple_ref/doc/uid/TP40013043-CH9-SW10
'Figure 2-4 A stretchable button texture' demonstrates how the (x, y, width, height) works.
Based on rwr's answer here is a working init method for a SKSpriteNode. I use this in my own game. Basically you make insets of 10px all around the the output image. And then call it like this:
[[HudBoxScalable alloc] initWithTexture:[atlas textureNamed:#"hud_box_9grid.png"] inset:10 size:CGSizeMake(300, 100) delegate:(id<HudBoxDelegate>)clickedObject];
-(id) initWithTexture:(SKTexture *)texture inset:(float)inset size:(CGSize)size {
if (self=[super initWithTexture:texture]) {
self.centerRect = CGRectMake(inset/texture.size.width,inset/texture.size.height,(texture.size.width-inset*2)/texture.size.width,(texture.size.height-inset*2)/texture.size.height);
self.xScale = size.width/texture.size.width;
self.yScale = size.height/texture.size.height;
}
return self;
}

UIScrollView - paging UIImage larger than the screens width

Am currently developing an iPad app which uses a UIScrollView. The UIScrollView is populated with UIImage(s) and all the images are larger than the iPads width, twice the width, 1536px. What I would like it to do is when swiped/flicked it will scroll to the second image, i.e. 1536 and the third image to 3072 and so on. Its just to see a quick image when sliding across. I've had a look at scrollViewDidEndDragging but it gets really nasty and jumpy at times.
Is there a way of setting the animation to scroll by 1536 each time apart from the last UIImage in the UIScrollView? I know you can use setContentOffset but if I use this in the above method it doesn't work as its using the current transition still and therefore making it very jumpy.
Edit
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"cocktail_%d.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.width = kMainImageWidth;
rect.size.height = kMainImageHeight;
rect.origin = CGPointMake(xpos, 0);
imageView.frame = rect;
[mainImgScrollView addSubview:imageView];
[imageView release];
xpos += kMainImageWidth;
}
Edit
All I needed to do was make the UIScrollView 1536px wide and it worked. The app will have 6 images to start with and more in the future. Hopefully there won't be a memory issue to start with?
Thank you for your help.
The page size is the UIScrollView size. It is perfectly acceptable to make the UIScrollView itself larger than the width of the iPad screen. If you make the UIScrollView 1536px wide, then each page will be 1536px wide.
To allow the user to scroll around and see each picture, what you want is a scrollview containing a row of scrollviews. The outer scrollview is the one in the window, it is 1536px wide, and it is just for paging. The inner scrollviews are the width of the screen and they have their contentSize set to the image size so that the user can scroll around in each one and see the image.
(However, you're going to want to rethink your architecture, since an app into which you have predrawn multiple images 1536px wide will not run (because it will exceed the available memory for the device). The WWDC2010 videos include an excellent talk on this very topic, i.e. how to design a paging scroll view that lets you page from image to image.)
I think you want to turn on paging on your UIScroll view. This will make it "snap" to the width of the scroll view. It will behave like the home screen on the iPad/iPhone does. You may need to make your scrollView's frame wider than the screen also to get the paging effect correct. You may encounter some lag no matter what due to the size of your images.

Resources