We have a background image for our app that needs to be full screen for each device we run the app on. Our problem is the background image is tiling on our iPhone 6S+ (Display Zoom off).
I have drawn in red lines to highlight where the tiling is occurring...
We have created 3 background images of the following sizes...
So, designing for 1x (which is the recommended way to go), our base level 1x background image is 320 pixels wide. Our 2x is 640 pixels, and our 3x is 960 pixels.
The problem is the iPhone 6S+ is 1080 pixels wide and according to this chart, you need to start with a 3x image that is 1242 pixels wide. And this is where I am missing how this is supposed to work.
from https://www.paintcodeapp.com/news/ultimate-guide-to-iphone-resolutions
With the above chart in mind, it seems you need a separate image for each resolution highlighted with a red square in the above image. Is this correct? And if yes, how do you label each individual image so that at runtime the correct one is picked?
Three images, named as you have them for background.png, are all you need.
Now let's talk about image views. They display their image using a content mode. The key thing is to pick the correct mode. Aspect Fill is what you probably want here, because it will fill the image view without distorting the image.
One procedure, then, is to use a bigger image than what you have, and configure the image view that shows the image to use an appropriate content mode such as Aspect Fill, so that it sizes the image down to fit (or, to save memory, at runtime you can size it down yourself).
The other possibility would be to leave your image as it is, and solve the issue on the Plus machines by telling the image view to size the image up to fit, again possibly by using Aspect Fill. That might or might not look acceptable; you'd have to try it and see what you think.
Related
I have read the 1x, 2x and 3x named image information for ios devices, but would that not cause scaling/image distortion when fitting it to an entire screen?
For example, the 3x can be handled by many iOS devices, but if you go from one to another, the screen resolutions/displays aren't a perfect 1 to 1 scale, so if I designed the 3x image to perfectly match say an iPhone 12, if another device uses the 3x image but with a different screen ratio, the background image fit to screen would then be skewed, correct?
Is there a way to avoid this? Some suggestions said have an image for every device/resolution and pick that image accordingly, but there is a long list of the devices, and it seems like overkill and a tedious solution. There must be something more elegant, unless I'm wrong.
You need to preserve the aspect ratio of the image when it is scaled to fit the UIImageView. You can do this by setting the image view's content mode to either aspect fit or aspect fill depending on your requirements.
I am having difficulties with retina images.
The screenshot below shows the UICollectionView with a UIImageView contained within each UICollectionViewCell.
Within the app I have a large image 512x512 pixels called travel.png.
The green circle shows what is displayed on the app when I name this file: travel.png. The blue circle shows what I see when I update the image name to be travel#2x.png (i.e. retina naming).
I was hoping due to the large size of the image (512x512) that simply adding the #2x suffix would be enough to convert it to twice the definition (i.e. retina) but as you can see from the two screenshots, both version images show as non-retina.
How can I update the image so that it will display in retina?
travel.png:
travel#2x.png:
* Updated *
Following request in comments below:
I load this image by calling the following function:
// Note - when this method is called: contentMode is set to .scaleAspectFit & imageName is "travel"
public func setImageName(imageName: String, contentMode: ContentMode) {
self.contentMode = contentMode
if let image = UIImage(named: imageName) {
self.image = image
}
}
Here is how the image appears in Xcode before the app renders it (as you can see it is high enough definition):
The reason why you see the low quality image is anti-aliasing. When you provide images bigger then an actual frame of UIImageView (scaleAspectFit mode) the system will automatically downscale them. During scaling some anti-aliasing effects can be added at curve shapes. To avoid the effect you should provide the exact image size you want to display on the screen.
To detect if UIImageView autoscale the image you can switch on Debug->Color Misaligned Images at Simulator menu:
Now all scaled images will highlight at simulator with yellow color. Each highlighted image may have anti-aliasing artifacts and affect CPU usage for scaling algorithms:
To resolve the issue you should use exact sizes. So the system will use them directly without any additional calculations. For example, if your button have 80x80px size you should add three images to assert catalog with following sizes and dpi: 80x80px (72 dpi), 160x160px (144 dpi) and 240x240px (216 dpi):
Now the image will be drawn at the screen without downscaling with much better visual quality:
If your intention is to have just one image for all the sizes, I would suggest it having under Assets.xcassets. It is easy to create the folder structures and manage media assets here.
Steps
On clicking + icon, you will displayed a list of actions. Choose to create a New folder.
Choosing the new folder that is created, click on the + icon again and click on New Image Set.
Choose the imageset. And choose the attributes inspector.
Select Single Scale, under Scales.
Drag and drop the image.
Rename the image name and folder names as you wish.
Now you can use this image using the image name for all the screen sizes.
TL;DR;
Change the view layer's minificationFilter to .trilinear
imageView.layer.minificationFilter = .trilinear
as illustrated by the device screenshot below
As Anton's answer correctly pointed out, the aliasing effet you observe is caused by the large difference in dimensions between the source image and the image view it's displayed in. Adding the #2x suffix won't change anything if you do not change the dimensions of the source image itself.
That said there is an easy way to improve the situation without resizing the original image: CALayer offers some control over the method used by the graphics back-end to resize images : minificationFilter and magnificationFilter. The first one is relevant in your case since the image size is being reduced. The default value is CALayerContentsFilter.linear, just switch to .trilinear for a much better result (more info on those wikipedia pages). This will require more GPU power (thus battery), especially if you apply it on many images.
You should really consider resizing the images before displaying them, either statically or at run-time (and maybe cache the resized versions). In addition to the bad visual quality, using such large images in quantities in your UI will decrease performance and waste lots of memory, leading to potentially other issues.
I have fixed, #DarshanKunjadiya issue.
Make sure (if you are already using assets):
Make sure images are not un-assigned
Now use images in storyboard or code without extensions. (e.g. "image" NOT "image.png")
If you are not using images from assets, move them to assets.
Demo Projects
Hope it helps.
Let me know of your feedback.
I think images without the #2x and #3x are rendered for devices with low resolutions (like the iphone 4 an 3G).
The solution I think is to always use the .xcassets file or to add the #2x or #3X in the names of your images.
In iOS, content is placed on the screen based on the iOS coordinate system. for displaying an image on a standard resolution system having 1:1 pixel density we should supply image at #1x resolution. for higher resolution displays the pixel density will be a scale factor of 2.0, 3.0 which refers in the iOS system as #2x and #3x respectively. That is high-resolution displays demands images with higher density.
For example, if you want to display an image of size 128x128 in standard resolution. You have to supply the #2x and #3x size image of the same. ie., 256x256 at #2x version and 384x384 image at #3x version.
In the following screenshot, I have supplied an image of size 256x256 for 2x version to display a 128x128 pixel image in iPhone 6s. iPhone 6s render images at #2x size. Using the three version of images such as 1x, 2x and 3x with asset catalogue will resolve your issues. So the iPhone will automatically render the correct sized image automatically with the screen resolution.
I understand how 1x, 2x and 3x image resolutions work but I'm unsure how I go about choosing the right size/resolution for custom images in general. Imagine that we have a simple layout like the following:
Now it is up to me to create the image (in Photoshop for example) for that UIImageView. What size and resolution should the highest quality version be? Do I just use the highest screen resolution of the iOS devices that are currently available as my guide?
There is not really a best size. As you said the highest screen resolution would be the maximum, because the device obviously can not display more pixels than it has provided. If the image view is only about 1/5 of the screen size then I would use a smaller image size for memory usage.
And you only need one size for background images for example. I normally place them in my assets folder into the 2x place and I am good.
For icons i use 25x25, 50x50 and 75x75 (which will display really small on the screen)
hope I could help you a little bit…
I have a very simple requirement here but I'm looking for a solution for a while. I want to take a profile picture form the camera roll or camera and display it in two different image views (different sizes). I don't want any of these images stretched or miss any part of the image. If I use aspect to fit, top side of image is cut from smaller image view and some parts missing on the bigger image view. If I set it as scale to fit, it will get stretched!
I'm not sure how some mobile apps work. Do they save different image sizes in their server or they change the size of the image. I saw many posts how to change image size without changing aspect ratio. But I don't think it is possible to avoid stretched effects. I used some of those code to change size of image, it gets stretched all the time.
Is there any way to save the image from camera roll one time with size of 140*200 and one time 160*200? So I can use 140*200 for image views that size. But what if I have different devices and different sizes.
In my iPhone app, I have a control that takes on quite different sizes on different screens. For example, (in the iOS point coordinates)
3.5 inch devices (iPhone 4S): 242x295
4 inch devices (iPhone 5 series, SE): 242x383
4.7 inch devices (iPhone 6 series): 297x482
5.5 inch devices (iPhone 6 Plus series): 336x551
As you can see, these control sizes are not proportional.
The problem
This control has an image as its background. That particular image is important for brand identity and the custom appearance that my company's designer wants to go with. The image gives the appearance of a material and has a texture. It also has shadows within itself. I would like to apply this image on to controls of different screen sizes (my control sizes are determined at runtime according to available space, as Apple may come up with new screen sizes anytime).
My current solution
The designer makes separate PNGs for me for each screen size and I hard code it with onto my control using an if-else for screen size (after determining the size mathematically before hand). As you can probably tell, this is a horrible approach for robustness. I'm also looking to expand to iPad and having a better scaling system will certainly help.
An idea
I take an image that's the smallest unit of the repeating texture and apply it to my control with the scaling option that repeats it throughout to obtain a final image.
HOWEVER, I lose my shadows and rounded edges this way. (I tried simply using the largest image as well and the disproportionate scaling makes the rounded edges horrible)
I tried looking for solutions and most resources do not deal with such images. I simply cannot lose any part of this image and it should be fully applied to the control, shadows and corners included.
I apologize if any or all of this is naive or if I didn't look for answers using the correct words. This is my first time posting here at Stack Overflow, and I'm looking forward to hearing from you guys.
Thanks!
p
Edit:
This is applied to a custom UIButton based control to give the appearance of a card.
Edit 2: Wain seems to have suggested a perfect answer. I will try it and let everyone know the results.
I'd use tiling as you describe, and I'd combine that with changing the view layer corner radius and applying a shadow offset. In this way you can separate the important part of the image and make it nicely reusable and you can leverage the capability of CALayer.
Note that when you set the shadowOffset of the layer you should also look at the shadowColor, shadowRadius and shadowOpacity.
You can used Assets.xcassets for managing images in ios. you can make image in 1x,2x and 3x scale.
For example you want an icon of size 50x50 pixel then 1x should be 50x50,
2x should be 100x100 and 3x should be 150x150. then ios automatically take appropriate image from this set.
Hope this will help :)
The aspect ration of iPhone 5, iPhone 6 and iPhone 6P are almost same. however the aspect ration of iPhone 4 is different.
Here is the steps which helps you.
So you need one image which image is suitable for iPhone 5 and its
#2x, and #3x image and iPhone 4 and its #2x image,
i.e if you have image with 242x383 for iPhone 5 then you need images
with its #2x, and #3x images. and you need image which is compatible
with iPhone 4 size.
You need to set UIImageView's contentMode as aspectFit.
So the idea is, make iPhone 5's image and its #2x, #3x images and iPhone 4's image differently. or you can put all things in UIScrollView and for iPhone 4 set contentSize of scrollView is 568. and make different image for iPad.