creating UIButton programmatically is blurry than using storyboard - ios

I have two custom UIButton with the same image.One is created programmatically which is blurry,the other is using storyboard which works fine.Here is the my code
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *purchaseButton=[UIButton buttonWithType:UIButtonTypeCustom];
purchaseButton=[UIButton buttonWithType:UIButtonTypeCustom];
purchaseButton.frame=CGRectMake(0, 35.5+30, 177, 55);
[purchaseButton setImage:[UIImage imageNamed:#"GouMai1.png"] forState:UIControlStateNormal];
[self.view addSubview:purchaseButton];
}
Here is the project download link(Because of GFW,I can only upload it to a Chinese website). Is that a Xcode bug?

purchaseButton.frame=CGRectMake(0, 35.5+30, 177, 55);
There's your problem. Never give an interface object non-integral coordinates. It will be blurry! - You'll notice that in Interface Builder (storyboard) you can't do that.
The reason is that on the screen there are physical pixels, and there is no such thing as half a pixel: every pixel is either on or off, as it were. So if you use half-point coordinates, they cannot match pixels exactly, and the system will blur things to match (antialiasing etc.).
So, get rid of the .5 and things will be much, much better.

Contrary to what #matt is saying, you can do .5 now so long as it's a retina device. You can even have .5 widths and heights, that's how iOS 7 gets their very thin lines in some places.
When I run your sample app, in the Retina iPad simulator it is not blurry (well no more blurry than the source image). But in the non-Retina iPad simulator it is blurry, and this is because of the .5 in the frame.
You need to test the scale of the screen [UIScreen mainScreen].scale and add the .5 only if the scale is > 1.
Also note, you are creating two buttons with that code. You can remove the duplicate line purchaseButton=[UIButton buttonWithType:UIButtonTypeCustom];

purchaseButton.frame=CGRectMake(0, 35.5+30, 177, 55);
Actually
Screen will have pixels and there wont be half pixel
The coordinates we specify for UI Elements will be points.
Point to pixel ratio will depend on dpi and ppi.
IOS primarily renders all things based on points and dpi and thus trying to use half point is causing blur. (Thats why we cant set the coordinates to points in interface builder)
So no floats are allowed forcing them causes blurness. please use nearest possible integer value.
On other hand since dividing even numbers with odd numbers will mostly give float point coefficients. we must use ceil and floor methods when performing calculations dynamically.
purchaseButton.frame=CGRectMake(0, ceil(self.view.fram.size.width/3), 177, 55);

Related

Ios image size guide for different iphones

I am just confused about the image sizes that I need to use for buttons, image views etc.
I want to adjust images for all iphones.
What should be ratio between the screen height/width and different iphones.
Like i have a button. I have created in following way-
UIButton *takePicButton = [UIButton buttonWithType:UIButtonTypeCustom];
takePicButton.frame = CGRectMake(0, SCREEN_HEIGHT-UI_ITEM_HEIGHT, SCREEN_WIDTH, UI_ITEM_HEIGHT);
[takePicButton setBackgroundImage:[UIImage imageNamed:#"take_photo.png"] forState:UIControlStateNormal];
[self.view addSubview:takePicButton];
[takePicButton addTarget:self action:#selector(takePicture:) forControlEvents:UIControlEventTouchUpInside];
for this button what size of images I need to add on xcode to support iPhone 4 - iPhone 7.
Thanks in advance.
Here is description about how image can set in iPhone:
• 1x images are for the original iPhone through the 3GS - 'standard' resolution devices (3.5" screens)
• 2x images are for the iPhone 4 and 4S (3.5" Retina screens) and are also used for the iPhone 5, 5s,6,6s,7
• 3x images are for the new iPhone 6+,7+ (5.5" super-Retina [3x] screen)
You have to keep three different types of image into your Assets.xcassets and just provide image name at where you want to display it. It will automatically take relevant image and display it.
You can check attached screenshots. You just have to write “bgImag” and it will take relevant image from assist.
About image ration, just create image for highest resolution of iPhone (i.e iPhone 6+), and just use iConify to get rest of image assest.
Try this, u can ask for two sizes. One is SCREEN_WIDTH * 2, UI_ITEM_HEIGHT * 2, the other is SCREEN_WIDTH * 3, UI_ITEM_HEIGHT * 3.Then put two sizes pics in your Images.xcassets named xxx#2x, xxx#3x.
I want to adjust images for all iPhones.
The easy way to do that is to use layout constraints. Your code tries to do what the constraints system would, given an appropriate set of constraints, but it's less flexible because it doesn't provide for changing geometry such as when the user rotates the device.
What should be ratio between the screen height/width and different iphones[?]
Different devices have different aspect ratios. There are lots of web sites (like this one) that list the screen sizes. When possible, though, it's best not to make any assumptions about screen size. New devices may be introduced with different aspect ratios, and even a single device may appear to have different screen sizes depending on how the user chooses to use it -- things like rotation and split screen affect the size and shape of the screen real estate that your device gets to use.
for this button what size of images I need to add on xcode to support iPhone 4 - iPhone 7[?]
We can't say without knowing what your UI_ITEM_HEIGHT constant is or what relative proportions you want for your button, but you should be able to calculate that yourself if you know the various screen sizes. You can use the reference I linked above, or this one, or one of the many others out there.
Read guide line for 1x, 2x, 3x
You should simply use:
UIImage *imButton = [UIImage imageNamed:#"image.png"];
[YOURBUTTON setImage:imButton forState:UIControlStateNormal];
Xcode will automatically use the available image with scales ex: #2x or #3x
From my example your images would be:
image.png (20x20 px),
image#2x.png, (40x40 px)
image#3x.png, (60x60 px)
respectively.
Quoting from apple:
Image Size and Resolution
iOS uses a coordinate system to place content onscreen. This
coordinate system is based on measurements in points, which map to
pixels in the display. On a standard-resolution screen, one point
(1/72 of an inch) is equal to one pixel. High-resolution screens have
a higher pixel density. Because there are more pixels in the same
amount of physical space, there are more pixels per point. As a
result, high-resolution displays require images with more pixels.
Refer here
Guys
You can try below code:
if (IS_IPHONE4) {
imgHeight.constant = 150;
}
else if (IS_IPAD) {
imgHeight.constant = 300;
}
else if (IS_IPHONE5) {
imgHeight.constant = 170;
}
else {
imgHeight.constant = 200;
}
Thanks.

Access iPhone Absolute Pixel Position

In the screenspace of an iPhone/iPad, Apple uses points, which are typically half the actual resolution of the screen. My question is, is it possible to access the actual pixels themselves? For example, if i take a UIView, and make it have a size/location of 0,0,0.5,0.5 with a background color of red, i can't see it on the screen.
Just wondering if this is possible.
Thanks!
Sure it's possible.
The code you already have should be working (a UIView with a size of (0.5, 0.5)). I just ran it and captured this result from the simulator:
Yea. That's difficult to see. Let's zoom that in.
So yes, you can draw on-screen in smaller values than a single point.
However, to draw a single pixel, you'll want to be using a point value that is 1/scaleOfScreen (as not all devices have 2x displays). So, for example, you'll want your code to look something like this:
CGFloat scale = [UIScreen mainScreen].scale;
CGFloat pixelPointWidth = 1/scale;
UIView* v = [[UIView alloc] initWithFrame:CGRectMake(20, 20, pixelPointWidth, pixelPointWidth)];
v.backgroundColor = [UIColor redColor];
[self.view addSubview:v];
This will now create a UIView that occupies a single pixel on-screen.
Although, if you want to be doing a lot of pixel-perfect drawing, you should probably be using something lower level than a single UIView (have a look at Core Graphics).
However.
You may encounter some issues with this method when drawing on an iPhone 6 Plus. Because it's screen's scale differs from its nativeScale, it will first render your content in the logical coordinate space of 3x and then downsample to the actual screen resolution (around 2.6x).
This will most probably result in some pixel bleeding, where your 'pixel' view can be rendered in neighboring pixels (although usually at a reduced brightness).
Unfortunately, there is no easy way around this problem without using an even lower level API such as OpenGL or Metal, where you can circumvent this automatic scaling and then downsampling, and draw directly into the screen's actual coordinate space.
Have a look here for a nice little overview on how different devices render content onto their screens.
Have a look here for more info on how pixel bleeding can occur on the iPhone 6 Plus.
You can guess the pixels based on the point depending on the device resolution (in ppi) by multiplying a coefficient but you don't want to do this.
Also, in your exemple you did not state that you normalized the coordinates so basically you are trying to display a red box at the first pixel (top left) with a size of half a point, which is why you can't see it.
EDIT
To draw a red box you can use this sample code :
// Draw a red box
[[UIColor redColor] set];
UIRectFill(CGRectMake(20, 20, 100, 100)); // position (x : 20, y: 20) (still top left) and size (100*100 points)

Displaying Images in iOS application

I need to display a few images in my IOS Application. What should I do so that the images display appropriately across all devices?
Do I have to set the size of the image manually based on the device? Please clarify.
You wouldn't use SpriteKit just to display images. You would load the images as UIImage and then create a UIImageView that you can place on the screen wherever and however you want and then you just assign the UIImageView your UIImage. UIImageView has a lot of properties you can set how images are displayed (e.g. if they are scaled and how they are scaled or if they are not scaled, how they shall be aligned within the viewable area, and so on). You can draw a UIImageView on top of a SpriteKit scene, that is no problem on iOS (on iOS everything is drawn by OpenGL ES or Metal anyway).
Of course you can also embed any image as a sprite if you like:
UIImages * img = ...;
SKTexture * tex = [SKTexture textureWithImage:img];
SKSpriteNode * sprite = [[SKSpriteNode alloc] initWithTexture:tex];
// If you don't use ARC, I'd add the following below:
// [sprite autorelease];
Now you can perfectly integrate it into the scene in whatever way you like an perfectly align it will all your other sprites. Yet if you just want to paint an image over the scene:
SKScene * scene = ...;
SKView * sceneView = scene.view;
UIImageView * imgView = [[UIImageView alloc] init];
imgView.image = img;
// Whatever content mode you prefer
imgView.contentMode = UIViewContentModeScaleAspectFit;
// Where shall it be placed and how big shall it be.
imgView.frame = CGRectMake(posX, posY, width, height);
// If you'd use this, it will cover the whole scene:
// imgView.frame = sceneView.frame;
// Add it on top of your scene
[[sceneView parent] addSubview:imgView];
// If you don't use ARC, don't forget to release it:
// [imgView release];
If you load an UIImage from your application bundle with [UIImage imageNamed:#"blah"] and the image exists in different resolutions for retina devices (blah.png, blah#2.png, blah#3.png), the system will automatically load the image it considers most suitable for the screen of the current device. This is nothing you have to deal with.
If you need to convert between scene coordinates and view coordinates, SKScene offers -convertPointFromView: and -convertPointToView: for this case. If the scene fills the whole screen, then these actually convert between scene and screen coordinates.
Even if devices have different resolutions, your scene can always have the same "virtual size". So you can always say that the scene is 400x300, no matter what the real screen resolution is. In that case placing a sprite of virtual dimension 200x150 at the virtual coordinates (100,75) will always center it on the screen, no matter what device or how big the screen really is (well, assuming that the SKSceneView really covers exactly the whole screne, of course). The size of a SKScene is just the coordinate system you want to have for layouting your game, it can be whatever you want it to be, it can be bigger or smaller than the real screen.
The scene is always drawn into a SKSceneView. The size of the SKSceneView is the real size of your scene in screen coordinates. So if you SKScene is 480x320 and the size of the SKSceneView is 1440x960, then moving a sprite one pixel in your scene will in fact move it 3 pixels on the screen. Yet if your SKScene is 1136x640, but your SKSceneView is only 586x320, then moving a sprite two pixels in your scene will only move it one pixel on screen. Your scene is always scaled up or down as required.
Personally I'd either stick with the same size across all devices or maybe just make two or three device classes but not adopt the game for every single device and every existing screen resolution.
There a lot of things to consider when dealing with images in SpriteKit, The short answer is you should be creating images in 1x, 2x, and 3x (background.png, background#2x.png and background#3x.png). You will get the best image quality if you do that.
As far as resizing images based on different devices that usually is done at the scene level. There are a lot of good SO questions out there that cover a lot of the questions you will have.
For example:
Dealing with different iOS device resolutions in SpriteKit
I recommend searching for "creating a universal app with SpriteKit".
Hopefully that answers your immediate question and helps get you started with the other questions you will have.

iOS: Keep real photo resolution when making screen capture with UIGraphicsGetImageFromCurrentImageContext

I want to make a basic photo editing in my application and now I need to be able to add a text over a photo. Original photo have something like >2000 pixels width and height so it will be scaled to fit in screen without modifying its ratio.
So , I put the image in an UIImageView, dragged a Label over it and then save the image on screen with UIGraphicsGetImageFromCurrentImageContext. The problem is I will get a small image (320 X some height).
What is the best approach to accomplish this task but not shrink the resolution?
Thanks a lot!
I had this exact same problem in an app.
The thing I realised is that you can't do this by doing a screen capture. In turn, this means that dragging labels and text onto the image can't really be done (it can but bear with me) with UILabels etc...
What you need to do is keep a track of everything that's going on data-wise.
At the moment you have the frame of your UIImageView. This, in reality is irrelevant. It is purely there to show the user a representation of what is going on.
This is the same for the UILabel. It has a frame too. Again, this is irrelevant to the final image.
What you need is to store the data behind it in terms that are not absolute and then convert those values into frames for displaying on the device.
So, if you have an image that is 3200x4800 pixels (just making it easy for me) and this is displayed on the device and "shrunk" down to 320x480. Now, the user places a label with a frame of 10, 10, 100, 21 with the text "Hello, world" at a particular font size.
Storing the frame 10, 10, 100, 21 is useless because what you need when the image is output is... 100, 100, 1000, 210 (i.e. ten times the size).
So, really you should be storing information in the background like...
frame = 0.031, 0.021, 0.312, 0.044
// these are all percentages
Now, you have percentage values of where the label should be and how big it should be based on the size of the image.
So, for the shrunk image size it will return 10, 10, 100, 21 and for the full image size it will be 100, 100, 1000, 210 and so will look the same size when printed out.
You could create a compound UIView by having a UIView with a UIImageView and a UILabel then you just have to resize it to the full image size before rendering it. That would be the easy but naive way of approaching it initially.
Or you could create a UIView with CALayers backing it that display the image and text.
Or you could render out the image and text with some sort of draw method.
Either way, you can't just use a screen capture.
And yes, this is a lot more complex than it first appears.

Adaptive Positioning Based on iOS Device

I made an iPhone game a few months ago, and am now trying to port it as a universal app to both the iPad and iPhone 5 with Cocos2D. I was wondering if there was a simple-ish way to determine where an object should be placed based on the device running the game.
I could use if statements to figure out which device the game is running on, so when I get the correct sized images for the device I could have separate positions for each object, but it seems like there would be a maths formula which would allow me to use a lot less code. Obviously something like a full screen background is very simple, because it just needs to be centred with:
[background setPosition:CGPointMake(screenSize.width/2,screenSize.height/2)];
I haven't a clue how to adapt a button that would be X = 144 & Y = 330 on the old 3.5inch, 640 by 960 resolution iPhone to an iPad or iPhone 5 resolution.
I'm willing to use a more recent version of iOS if it will make my life easier, but because I'm not using any of Apple's objects I don't know if that is possible.
Maybe this isn't even possible because the button will be different sizes for the iPhone and iPad version, but I thought I would ask.
yeah, i am usually facing the same problem,
but if it is just a static objects placement
i would have relative coordinates instead of absolute for every object
and then use screen sizes to place them correctly
so you might want to use a function like:
-(CGPoint) relativeToScreen:(CGPoint) p {
return ccp(screenSize.width * p.x, screenSize.height * p.y)
}
where 0.0 <= p.x =< 1.0 and the same for p.y
and don't forget about your anchorPoint, because the node position is based on it as well
and i hope you have discovered that cocos2d already does image choosing instead of you,
you just have to set right suffixes for your images: -hd, -ipad, -ipadhd
For iphone5 resolution, I position hud buttons relative to the screen dimensions. Very similar to what you are doing for the background. So for example, a pause button I want in the top left I would position like this:
[pauseButton setPosition:CGPointMake(0.0f + 30.0f, screenSize.height - 50.0f)];
For ipad it gets really tricky. The lazy way which I have implemented is to play around with the content scale factor and zoom everything up and have "dead" borders to compensate for the ipad's screen ratio. Not the best, but at least you can re-use all the same assets for the ipad.

Resources