images render larger when loaded programmatically on iPhone X,Xs?

381 Views Asked by At

Has anyone had an issue with images rendering larger when loaded programmatically on iPhone X,Xs?

If I add an image in the storyboard it resizes correctly, however if I load it programmatically it will appear larger. I am using the Xcode 10.1. I have tried both a launch.storyboard and launch images to verify I am correctly accessing the iPhone X,Xs.

The images load correctly on XsMax and XR. I know X,Xs renders pixels differently. This is a single image, I do not use @2x, @3x etc...

If I put a UIImageView element in the storyboard view and its Frame Rectangle is (3,95) and (130x253) the image looks correct in the storyboard and when I run the simulator. If I load the same image but do it programmatically such as:

UIImageView *dot =[[UIImageView alloc] initWithFrame:CGRectMake(3,95,130,253)];
dot.image=[UIImage imageNamed:@"apple.png"];
[TestView addSubview:dot];

The programmatically UIImageView looks larger than 130x253. Maybe a 1/3 larger?

Thank you

1

There are 1 best solutions below

4
On BEST ANSWER

This is an x-y question: you've misidentified the problem. The image view that you add in code is always coming out the same size on all devices. The problem is the other image view, the one that you are adding through the storyboard: that is the one that changes size on different devices. And the reason is: that's what you've told it to do, with your autoresizing settings, which look like this (I've taken this directly from the project you posted for me to look at):

enter image description here


I'll prove this in two stages. First, let's talk about only the image view added in code. Here's my scientific test code (it's in Swift but I'm sure you can read it):

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        for i in stride(from: 0, to: 500, by: 100) {
            let v = UIView(frame:CGRect(
                x: CGFloat(i), y: 20, width: 10, height: 50))
            v.backgroundColor = .black
            self.view.addSubview(v)
        }
        let im = UIImage(named:"bullwinkle2.jpg")!
        let iv = UIImageView(frame:CGRect(
            x: 0, y: 50, width: im.size.width, height: im.size.height))
        iv.image = im
        self.view.addSubview(iv)
    }
}

You see what I'm doing? First I build a kind of "ruler" out of black subviews spaced 100 pixels apart. Then I create the image view and add it, specifying the width and height of the image.

Here's how it looks on the iPhone 5s simulator:

enter image description here

Here's how it looks on the iPhone X simulator:

enter image description here

As you can see, they both show the same size image: the width of the image comes exactly to the third mark on both devices (the image must be exactly 200 pixels wide).


Okay, on to stage two. Now I'll add an image view in the storyboard, using your autoresizing settings with springs internally, both horizontally and vertically:

enter image description here

Now I'll run the same code again on an iPhone 8 simulator:

enter image description here

The two images appear the same size, because I designed the interface in the storyboard when the view was sized for iPhone 8.

Okay, but now let's run again on an iPhone 5s simulator:

enter image description here

Aha! The storyboard image is smaller, because of the autoresizing settings. So you see, it's not that the code image is coming out too big; it's that the storyboard image is sometimes coming out too small.


Final note: your ultimate goal is to create the image view in code at the same size that the image view from the storyboard is coming out. But the reason that doesn't always work is that you've put that code into viewDidLoad, which is too soon. You don't know the storyboard image view size until autoresizing has taken effect, which means that viewDidLayoutSubviews has to have been called. That happens later than viewDidLoad.