AutoLayout for CGRect for Universal App - ios

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.

Related

UIScrollView Lazy Loading Images

My app for the iPhone Contains 170 images. I read them into an array, and in the loop add a picture in the viewfinder, then put the image View as sub view of scroll view.
When running my app uses too much memory 700mb. I tried to reduce the size of the pictures, but it didn't work.
One of my friends said that I should add only images # 1 and # 2. When the user block is scrolled to the picture No. 1, then only show the picture No. 2. Then the picture No. 1 to remove from the image viewer and add the picture No. 3.
He says that in this way I can maintain the normal memory consumption. But I don't understand how to do this?
Could you help with an example? Thanks in advance.
Not using UICollectionView
Here is my code:
- (void)addImageViewToScrollView {
_assetsArray = [[NSMutableArray alloc] init];
for (int j = 0; j < 170; j++) {
[_assetsArray addObject:[UIImage imageNamed:[NSString stringWithFormat:#"%d",j]]];
}
//scrollView add subview ImageView
for (int i = 0; i < [_assetsArray count]; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width *i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
_imageView = [[UIImageView alloc]init];
_imageView.image = [_assetsArray objectAtIndex:i];
_imageView.frame = frame;
[self.scrollView addSubview:_imageView];
}
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * self.assetsArray.count, self.scrollView.frame.size.height);
}
--
Use a UICollectionViewController to solve this issue.
This way only the cells that are required on screen are loaded and all others images are can be popped from cache when you hit a memory warning.
Collection Views work very similar to table views.
To get the collection view to suit what you're doing you'll need to set the flow layout to horizontal scrolling and set the cell sizes to your view's height and width.
Seems like you are trying to add170images onto UIScrollView using UIImageView. Why not use dedicated UITableView's or UICollectionView's? Object of Reusable Cell is to maintain run-time memory consumption. Let's recap on this,
You have 170 ImageViews (_assetsArray) ; expensive consumption
You have 170 Images
Versus, Using UITableView or UICollectionView
You have 1 ImageView in a Cell with 170 rows
You have DataSource of 170 Images were loaded
Your cell will be re-cycled when it needed to display correspond to DataSource
Also, for supporting the multitude images, there are good libraries to reduce images cache. Try to use SDWebImage or FastImageCache. I personally like FIC but you might need to understand the concept.

How to create relative constraints in xcode 5?

Hello, i want to create relative constraints between 3 elements.
And when resized from 4 to 3.5inch those constraints resizing to the new size while objects keep their size;
There is a way to create flexible spacing between elements with the help of constraints. The way is to use a view for the spacing not a constraint. There is event a sample in the official documentation.
https://developer.apple.com/library/ios/documentation/userexperience/conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html
Look at the section named "Spacing and Wrapping".
Don't use static height and width. use following code for calculating height and width.
int width = self.view.frame.size.width;
int height = self.view.frame.size.height;
In this way set X and Y co-ordinate for your element.
Refer this Code -
int imageX = 2,imageY = 2;
int count1 = 0;
for (int i = 0; i < [mainMenuColumn1Array count]; i++) {
count1++;
MenuClass *menuClass = [[MenuClass alloc] init];
menuClass = [mainMenuColumn1Array objectAtIndex:(count1 - 1)];
UIButton *menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(imageX, imageY, (width/2)-4, (height/3)-4);
menuBtn.tag = count1;
[menuBtn addTarget:self action:#selector(mainMenu1Action:) forControlEvents:UIControlEventTouchUpInside];
menuBtn.backgroundColor = [UIColor colorWithRed:17.0/255.0 green:116.0/255.0 blue:239.0/255.0 alpha:1.0];
[mainView1 addSubview:menuBtn];
imageY = imageY + height/3;
imageX = 2;
}
Here I have add UIButtons dynamically. And I set XY co-ordinates dynamically. This is a generic code for all size devices.
You can't do this in interface builder, as far as I am aware, because you can't specify multipliers on constraints via interface builder. However, you can do it quite easily in code, particularly using a nice auto layout helper category available via Github or cocoapods. (Disclaimer - I wrote the category!).
The category contains a method to distribute an array of views evenly along a specified axis, and under the hood it creates constraints using multipliers of the containing view's dimensions - so for two views, the centres would be 0.33 and 0.66 of the way along the relevant axis, for example.
To use this for a view primarily built in interface builder, you'd use placeholder constraints (removed at run time) then add the category constraints after viewDidLoad.

Giving absolute values to ui component - doesn't work for iPad

I have added a text box programatically. My code is as follows:
t = [[UITextField alloc] init];
[t setFrame:CGRectMake(55,200,200,50)];
[self.view addSubview:t];
When i run it on the iPhone simulator it works perfectly (the textfield positioned at the exact point that i want), but when i run it on the iPad the positions are not proper. I was thinking that it will auto adjust it self when the screen size increase/decrease. How am i going to correct this ?
note: I am not going to use interface builder or story board.
Setting absolute values work just as expected. That’s why the are called absolute values. The problem are flexible/dynamic values.
It will not adjust automatically until you tell it to do so. Here are your options:
Manually check for User Interface Idiom and set two different values. This is the correct way of detecting iPhone and iPad UI:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) ...
(Create some function for this.)
Calculate the values based on screen or superview size:
CGSize screen = [[UIScreen mainScreen] bounds].size;
frame.size.width = screen.width / 2 - 40;
Set autoresizing mask, which set up rules on now subviews are resized, when superview changes size:
view.autoresizingMask = UIViewAutoresizingMaskFlexibleWidth;
Must be combined with some fixed or calculated frame values. Autoresizing is useful only when the view resizes, not when you set it for the first time, so this is not exactly your case. For full description of how this works, see UIView documentation.
Use Auto Layout, which is powerful, but quite complex soluton to dynamic layout. At first you would need to read about it and experiment to fully understand how to use it.
If you have a view, whose size and position cannot be described with some kind of rules, you will have to write the coordinates directly (option 1).
Hey mate please use the below code if you are not comfortable using the storyboard or xib file.
NSString *deviceType = [UIDevice currentDevice].model;
t = [[UITextField alloc] init];
if([deviceType isEqualToString:#"iPhone"]) // For iPhone
{
[t setFrame:CGRectMake(55,200,200,50)];
}
else // For iPad
{
[t setFrame:CGRectMake(55,200,600,100)];
}
[self.view addSubview:t];
Hope this helps you.

How do I hide controls and cause others to shift place in iOS?

I'm programming an app for iOS 7 in Xcode 5.
I have three text boxes at the top of my page, each right above the other. Let's call them topTextBox, middleTextBox, and bottomTextBox.
My intent is that depending on a particular condition, the topTextBox might not be visible (or present, really) when the view loads.
If topTextBox isn't present (or hidden, or whatever) I would like middleTextBox and bottomTextBox to be placed further up the page...as if topTextBox wasn't ever there in the first place (so middleTextBox is in the spot topTextBox used to be in, and bottomTextBox is in the spot middleTextBox was in).
I'm using storyboards with AutoLayout ON. I can't seem to figure out what to do with the constraints for each of the three textBoxes to make this work. Making middleTextBox and bottomTextBox sit higher on the page when topTextBox is hidden doesn't need to be dynamic--I make the decision to show or not show topTextBox in ViewDidLoad()--I just need to get them to show up in the right place depending on my conditions.
Questions:
a. Is making topTextBox.hidden = YES the right way to get topTextBox to not be shown? Or is there some way to make it not noticed by the view at all?
b. What do I do with these constraints on middleTextBox and bottomTextBox to move them up on the page in this condition?
c. Is there anything else I should know to get this to work that I'm not thinking of? Perhaps a better method?
Thanks.
Have you tried just hard coding the frame logic? This could be very effective. All you have to do is conditionally populate an array containing pointers to your text fields and then perform a little frame arithmetic on their y origins. For example, this could easily display all the fields:
NSArray *fields = #[topTextField, middleTextField, bottomTextField];
for (int i = 0 ; i < fields.count ; i ++) {
UITextField *field = fields[i];
[field setFrame:CGRectMake(20.0, 20.0 + (i * 50.0), 280.0, 34.0)];
}
Produces this:
Or at its most basic level, something like this could be used to check whether any of the text fields should/shouldn't be shown, and either hides them, or adjusts their frame accordingly.
BOOL shouldShowTop = YES;
BOOL shouldShowMiddle = NO;
BOOL shouldShowBottom = YES;
NSMutableArray *fields = [NSMutableArray new];
if (shouldShowTop) {
[fields addObject:topTextField];
}else{
[topTextField setHidden:YES];
}
if (shouldShowMiddle) {
[fields addObject:middleTextField];
}else{
[middleTextField setHidden:YES];
}
if (shouldShowBottom) {
[fields addObject:bottomTextField];
}else{
[bottomTextField setHidden:YES];
}
for (int i = 0 ; i < fields.count ; i ++) {
UITextField *field = fields[i];
[field setFrame:CGRectMake(20.0, 20.0 + (i * 50.0), 280.0, 34.0)];
}
Will produce this:
Setting the height constraint of topTextField to 0 will help you to achieve this.
provided all textfields are connected through vertical space constraint
Setting the height of topTextField so that it has zero height could also work for you.
CGRect frame = topTextField.frame;
frame.size.height =0;
topTextField.frame = frame;
This is a good choice should you want to animate its re-appearance later on.
As for constraints, constrain the top of the topTextField to the superview, and then the top of middleTextField and bottomTextField to the bottom of the textfield above.
Do not set a constraint for the height of topTextField, but do set width constraints. You'll need to set the height of topTextField in viewDidLoad:

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

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.

Resources