UIButton Shrinking on iPad OS 7.0 - ios

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;
}

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

How to handle Image sizes on different devices

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

How to get image without resizing?

first of all i need to describe what i gonna to do:
i need to display a header image with full screen width for all devices.
there for i should provide multiple pictures with different sizes, and not just 2x and 3x.
so i would have these images:
header_width_1242.png for iphone 6 plus.
header_width_1125.png for iphone 6 plus display zoom
header_width_640.png for iphone 5,6
...
so i shouldn't choose image according to the scale, rather i should choose image according to the width:
let image_name = "header_width_" + String(UIScreen.mainScreen().scale * UIScreen.mainScreen().bounds.width)
let image = UIImage(named:image_name)
the problem, that ios scale the image automatically again. so if the device with scale 2x. then it return the image * 2 size.
e.g : for iphone 5 which has width 320 and scale 2, i need the header_width_640.png , but it seems that the system scale the image to 1280 (640 * 2).
How could i tell the system, to return image UIImage(named:image_name) without scaling ?thanks
You could declare a screenSize property on your viewController.
// Determine screen size
let screenSize: CGRect = UIScreen.mainScreen().bounds
Then, when you need to set an image, you could do the following:
if screenSize.width < 641 {
// set your imageView to the image for 640 screen width
} else if screenSize.width < 1126 {
// set your imageView to the image for 1125 screen width
} else if screenSize.width < 1243 {
// set your imageView to the image for 1242 screen width
}
You should not constraint assets by screen size, is better if you do by using size classes if available. Image assets directory make this possible in the inspector panel, by choosing the size classes for each image.
I do understand that sometimes is a need, but try to think in a relative perspective. If the image is something like a logo aligned by left or right you can use slicing to create stretchable end/beginning on the image.
If the image is center with a solid color or something drawable by code you can draw it at run time.
Here is a snippet in ObjC that use in an app of mine you can easily convert in SWIFT:
-(UIImage*) createNavBarBackgroundWithImage:(UIImage*) image {
CGSize screenSize = ((CGRect)[[UIScreen mainScreen] bounds]).size;
CGFloat width = screenSize.width;
CGFloat height = 64.0;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 0.0);
//Draw background
UIColor * backGroundColor = [UIColor colorWithRed:27.f/255.f green:142.f/255.f blue:138.f/255.f alpha:1.0];
[backGroundColor setFill];
UIRectFill(CGRectMake(0, 0, width, height));
//Draw the image at the center
CGPoint point = CGPointMake(width/2 - image.size.width/2, 0);
[image drawAtPoint:point];;
UIImage *newBGImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newBGImage;
}
Use Image Asset
https://developer.apple.com/library/ios/recipes/xcode_help-image_catalog-1.0/chapters/AddingImageSets.html
header_width_1242.png for iphone 6 plus. Name it header_width_414.png drag to 3x
header_width_1125.png name it header_width_375.png drag to 3x
header_width_640.png name it header_width_320.png drag to 2x
let image_name = "header_width_" + UIScreen.mainScreen().bounds.width)
let image = UIImage(named:image_name)

IOS7 image losing quality when rendering UIView [duplicate]

UIImageView *cellimage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0 , 107, 70)];
The above statement i am sure will make appropriate sizes in both retina resolution devices and standard ones..that is a frame of 107 x 70 pixels on standard and 214 x 140 on retina.
What i want to know is if the below UIGraphicsGetImageFromCurrentImageContext does the same too.. image will be 67 x 67 for standard and 124 x 124 for retina versions?
CGSize imagesize = CGSizeMake(67, 67);
UIGraphicsBeginImageContext(imagesize);
NSLog(#" Converting ");
[image drawInRect:CGRectMake(0,0,imagesize.width,imagesize.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if not can anyone tell me how to differentiate between models.?
Thanks
You need to use UIGraphicsBeginImageContextWithOptions instead of UIGraphicsBeginImageContext, so that you can specify the scale factor of the image. This will use the scale factor of the device's main screen:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
This will use the scale factor of the screen containing cellImage, if cellImage is on a screen:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, cellImage.window.screen.scale);
This will hardcode the scale factor:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 2);

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