How to handle Image sizes on different devices - ios

Currently, i am doing this type of view, What is the best way so i can manage the image in different size of scale
We have this sizes,
Device Points Pixels Scale Physical Pixels Physical PPI Size
iPhone 6 Plus 736x414 2208x1242 3x 1920x1080 401 5.5"
iPhone 6 667x375 1334x750 2x 1334x750 326 4.7"
iPhone 5 568x320 1136x640 2x 1136x640 326 4.0"
iPhone 4 480x320 960x640 2x 960x640 326 3.5"
iPhone 3GS 480x320 480x320 1x 480x320 163 3.5"
My Problem is image coming from server i want to handle this image in all type of device of Apple, I am using aspect fit in cell and when i am using 640 * 106 size then in i-phone 6plus this images are are not showing correctly size
Here's my code
CGRect frameIphone = (flag) ? CGRectMake(0, 0, self.view.frame.size.width, 106):CGRectMake(0, 0, self.view.frame.size.width, 106);
UIImageView *img = [[UIImageView alloc] initWithFrame:(iPad) ? CGRectMake(10,8,55,55) : frameIphone];
img.tag = indexPath.section;
img.contentMode = UIViewContentModeScaleAspectFit;
img.layer.masksToBounds = YES;
[img sd_setImageWithURL:[NSURL URLWithString:[objClass getImageForBackground]] placeholderImage:nil]; // URL Images

Its not that hard really, because what you doing is fixing the width/height of the view, what you need to do is calculate based on the screen ratio and give it correct height since the width is fixed based on the screen width, example if the screen is iphone 6plus, which have point of 736x414, and the image is 640x106, you do a calculation 736*109/640 (screen width * image height / image width, change with variable) = 125, thats the imageView height you should use, not 106 directly
You can set the image to the image view first then config it's frame also ok, so you can get the image height/width

Related

On iOS, why is 100 "points" a different size on different devices?

It was my understanding that if you specified a size of 100 points in iOS, that it should be interpreted as "100 density independent pixels", such that it would take up the same amount of physical space on the screen, independent of the device.
So if 2 devices had the same pixel density, each mapping 1 point to 2 pixels, 100 points would take up 200 pixels on those devices and they would appear to be the same physical size. If Device_B has 2x the pixel density of Device_A (and device A is 1:1 pixel:point) then 100 points would take up 100 pixels on Device_A, and 200 pixels on Device_B which would consume the same physical screen real-estate. Am I missing something?
I tested a UILabel of size 100x30 on an iPhone 6 and an iPad Air 2, and they definitely don't take up the same physical size on the screens - the 100x30 label on the iPhone 6 screen looks to be about 2/3 the same physical size compared to the iPad.
Here is the very simple test code
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor:[UIColor blueColor]];
UILabel *testLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 100, 30)];
testLabel.text = #"Test Label";
testLabel.backgroundColor = [UIColor greenColor];
[self.view addSubview:testLabel];
}
I've attached an image of the 2 physical devices rendering the same label (iPad left, iPhone on right).
Ppi is pixel per inch where pixel means physical device pixels.
iOS screen scale factors 1x, 2x, 3x means only relation between physical pixels and screen points (density independent pixels). What even not 100% correct for iPhone6&7 plus where screen points rendered in x3 scale pixels and then this is downsampled with factor 1,15 to real screen pixels.
iPad Air 2 ppi = 264
iPhone 6 ppi = 326
Both have scale factor 2x. So label with size 100x30 will have size 200x60 in physical pixels on each of devices.
And
200/264 x 60/264 = 0,76 X 0,23 inches on iPad
200/326 x 60/326 = 0,61 X 0,18 inches on iPhone6

Xcode asset catalog support for 3.5", 4", and 4.7" #2x images?

Xcode offers asset buckets for 1x, 2x, 4" 2x, and 3x assets. My fullscreen assets are all wonky with this configuration, because the 2x bucket is used for 3.5" and 4.7" screens. Currently I have a UIImage category that introspects the current screen size, and selects a "*-3.5" asset if the device seems to be 3.5".
This is clunky and not cool. Seeing that Xcode caters to all the different device sizes for their LaunchImage asset, I was hoping there was some way to supply device specific assets for non launch image assets without resorting to code.
I have reported a bug to Apple about this since mid November 2014 and I just noticed they marked it as No Value... which gives me the impression Apple has omitted an additional slot for iPhone 6 on purpose. My guess is they now want the 2x slot to be used for iPhone 6, and maybe they're reducing support to iPhone 4s as it's getting old.
If you really want to keep supporting the iPhone 4s, I'd suggest to use iPhone 6 sized images in the 2x slot, and then use the following method to load your images:
+(UIImage *)loadImageNamed:(NSString *)imageName
{
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGFloat screenHeight = MAX(screenSize.width, screenSize.height);
CGFloat const IPHONE_4_SCREEN_HEIGHT = 480;
UIImage *image = [UIImage imageNamed:imageName];
if(screenHeight == IPHONE_4_SCREEN_HEIGHT) {
CGFloat const xScale = .85333333;//x conversion ratio from iPhone 6's 375 pts width screen to iPhone 4's 320 pts width screen
CGFloat const yScale = .71964018;//y conversion ratio from iPhone 6's 667 pts height screen to iPhone 4's 480 pts height screen
CGSize newSize = CGSizeMake(xScale * image.size.width, yScale * image.size.height);
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
[image drawInRect:(CGRect){0, 0, newSize}];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resizedImage;
}
return image;
}
Resizing a big image (iPhone 6) to a smaller one (iPhone 4) doesn't lose much quality even if the aspect ration is not the same.
Using an existing project when moving to Xcode 6 and iOS 8 creates some initial issues. I solved this by changing the image set from Device specific to Universal. This removes the R4 image option and leaves you with #1x, #2xand #3x. If you use for example a background image that needs to fit the screen then I will recommend that you find an image that does not have to fit 100 % perfect to look good, and set image to be displayed as Aspect Fill.
I have the same problem and got confirmation from apple that I have to wrote code for that. For example you can try like this Fullscreen images on iPhone 6 with Asset Catalogs
But I actually went lazy about it by using one 2x for 4" & 4.7" screen and another 2x for 3.5" screen

UIButton Shrinking on iPad OS 7.0

I am running into an issue with a custom UIButton Image and my iPads 2/3:
The Problem
I create a button from an image that is size 72 x 72 px. I set a button frame to the same size of the image. When I run the code in iOS simulator a 72 x 72 px button appears (scaled at 50%). However, when I run the code on my iPad the button is scaled down from 72 x 72 px to approximately 45 x 45 px? When I take a screenshot of the iPad screen, the correct size of 72 x 72 px is shown when scaled to 50% I need the button to be 72 x 72 px on the iPad, how can it be fixed? or can it be fixed? Is an image automatically scaled because of the size of the device?
Fix Attempts
I added a 2x image to accommodate retina, makes the image bigger but not 72 x 72
I changed the resolution of the images from 300 dpi to 72 dpi and no change.
Looked at this solution: UIButton Shrinking Image. My image has has an alpha channel, so there was no fix
Looked at this solution: custom UIButton image is getting reduced (shrinked) in iphone OS 4.0. As far as I know, my image does not have any blank borders
Materials
iPad 3 (retina) running iOS 7.0 /iPad 2 running ios 7.1.1
Images: RedTarget.png / RedTarget#2x.png
Dimensions: 72 x 72 px / 144 x 144 px
Resolution: 299 pixels/inch
Alpha Channel: Yes
Color Space: RGB
Simple Code Used
UIImage *img;
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
img = [UIImage imageNamed:#"RedTarget#2x.png"];
}
else
{
img = [UIImage imageNamed:#"RedTarget.png"];
}
CGFloat h = img.size.height;
CGFloat w = img.size.width;
UIButton* targetbutton = [[UIButton alloc]initWithFrame:CGRectMake(512,384, w, h)];
NSLog(#"%f %f", w, h);
[targetbutton setImage:img forState:UIControlStateNormal];
targetbutton.center = CGPointMake(512,384);
NSLog(#"%#", targetbutton);
[self.view addSubview:targetbutton];
When I run this code on my iPad 3, the NSLog statements print as the following:
2014-05-14 10:19:40.511 TestSizeButton[574:60b] 144.000000 144.000000
2014-05-14 10:19:40.515 TestSizeButton[574:60b] <UIButton: 0x16d495a0; frame = (440 312; 144 144); opaque = NO; layer = <CALayer: 0x16d49730>>
Thanks in advance for your help!
Try to add your button at viewWillAppear or viewDidAppear method and check whether if it further shrinks or not. Also check whether the position of view is shifting or not while loading. If your view is shifting then add this in your viewDidLoad method
if( [self respondsToSelector:#selector(setEdgesForExtendedLayout:)] )
{
self.edgesForExtendedLayout=UIRectEdgeNone;
}

Retina simulator displays non-retina resolution

In XCode, I have set my IOS simulator as iPhone (Retina 3.5-inch). However in my code, when I display the screen dimensions (using Bounds CGRect), I get 320 x 480 instead of expected 640 x 960.
Any idea why ?
I am using the latest XCode and output is named iPhone 6.1 Simulator.
Thanks.
Try this:
UIScreen *mainScreen = [UIScreen mainScreen];
UIScreenMode *screenMode = [mainScreen currentMode];
CGSize realSize = [screenMode size];
Frame and bounds are measured in points not pixels. On retina devices, 4 pixels will be in 1 point while non-retina devices have 1 pixel for every point.

Using one image png file for retina and normal screen in UIImageView

Say there is cool.png file with dimension 200 X 100 pixels and I'd like to use it for both retina and normal devices.
I need to get size of UIImageView 100 X 50 points.
I tried to decrease the size of UIImageView according to image dimensions and visually I don't see any difference whether I prepare two file with and without scale modifier #2x or use UIImageView to scale it by contentMode property.
BOOL retina = [[UIScreen mainScreen] scale] == 2.0 ? YES : NO;
UIImage *img = [UIImage imageNamed:#"cool.png"];
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
imgView.contentMode = UIViewContentModeScaleToFill;
CGFloat width = img.size.width;
CGFloat height = img.size.height;
if (!retina) {
width = width/2.0;
height = height/2.0;
}
imgView.frame = CGRectMake (somePoint.x, somePoint.y, width, height);
Is there something wrong in the approach?
You are taking the wrong approach here..
CGRect,Point and Size aren't measured in pixels.. They are points.. Points are iOSes coordinate system and will be scaled to the device... So for example if you make a UIView 320 points wide then it will fill the width on both a retina iPhone or iPad...
so if you want your cool.png to display at 100x50 points on all devices then you can simply set the frame to be 100x50, set the image to cool.png then set the imgView.contentView to UIViewContentModeScaleAspectFit... This will then rescale the 200x100 image to fit of its a non retina device... Then if it was a retina device it would be at full resolution (200x100) but in the 100x50 points...
However the #2x system was made for a reason as having to scale the images down increases loading times as it has to be scaled but if you can't use #2x images then you can still do the above

Resources