0

I am developing an ObjC iPhone app in Xcode 6, targeting iOS 7 as the minimum version.

I have fullscreen background images for the main UIViewController instance in my app. The app uses four visual themes, and each background now comes in three sizes. To support 4", 4.7", and 5.5" screens, the image widths are 640, 750, and 1242 pixels respectively. In my project, I choose a specific image based on the result of [[UIScreen mainScreen] nativeBounds] to get the background image corresponding to the screen resolution. For example, background_gray (for 640 pixels), background_gray_750, and background_gray_1242.

Is there a way I can arrange all of my background images in an Xcode xcassets bundle so each device will only get the background images it will use? In other words, the backgrounds with pixel widths of 750 and 1242 pixels will never get used on a 3.5" or 4" screen.

Both the 640-pixel 750-pixel width images are 2x, so this isn't a matter of simply specifying 1x, 2x, and 3x versions of one image using the same name.

bneely
  • 9,083
  • 4
  • 38
  • 46

4 Answers4

4

I recently faced this situation too and pondered why Apple didn't include a Retina 4.7 2x option in the device-specific image set.

Rather than creating an image set for each size variation, as you described, I used two image sets per image: one which contains images for 1x, 2x, Retina 4" 2x, and 3x like this:

enter image description here

And one for the iPhone 6 (Retina 4.7" 2x) image, like this:

enter image description here

This way I only need to check for the screen width that matches the iPhone 6, like so:

CGFloat screenWidth = CGRectGetWidth([UIScreen mainScreen].nativeBounds);
NSString *imageName = (screenWidth == 750.0) ? @"Image~750" : @"Image";
UIImage *image = [UIImage imageNamed:imageName];

The false condition in the above ternary operator defers to the OS to pick the correct image to display from the first image set above.

neilco
  • 7,964
  • 2
  • 36
  • 41
  • I thing apple didn't include 2x because the simple reason that there is no 4.7" and 4.7 retina... 2x images were born when iPhones with retina screens came out. – KnF Oct 08 '14 at 16:43
  • @KnF That does not explain the lack of Retina 4.7 support. – neilco Oct 08 '14 at 16:47
1

No, there is only a single application bundle distributed to the store for all devices iPhone 4 through iPad. This bundle will need to hold your images for all devices.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • To clarify, I am asking about specifying the images within the `xcassets` bundle (I only use one) rather than using device-specific `xcassets` bundles. – bneely Sep 25 '14 at 22:25
  • 1
    I don't understand - in your question you say "each device will only get the background images it will use" - All devices will get all images regardless of whether they are in a single xcassets bundle or multiple xcassets bundles or just resources added to your app – Paulw11 Sep 25 '14 at 22:47
  • Oh in that case I don't have to do anything - if I can't affect the set of installed images, what I'm doing now is correct. Thank you! – bneely Sep 25 '14 at 22:49
1

I have 27 apps in the store and did not want to create and manage new backgrounds for each of them. And I suspect that there will be more sizes in the future. So what I did was create an 1800x1800 image for each app. They are mostly around 300-400KB. It works for me because there is lots of white space around the image. I basically put a square image in the center of the screen. If you want to fill up the whole screen, then this method won’t work. Then in viewWillAppear I call this method.

- (void)pickBackgroundImage {

    UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
    CGFloat scale = [UIScreen mainScreen].scale;
    CGPoint midPoint = [Utilities findMidpoint:self.view];

    NSString *pictFile = [[NSBundle mainBundle] pathForResource:@"Background" ofType:@"png"];
    UIImage *imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
    imageToDisplay  = [UIImage imageWithCGImage:imageToDisplay.CGImage scale:scale orientation:imageToDisplay.imageOrientation];

    CGRect pictFrame;
    if(orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
        CGFloat imageWidth = (unsigned int)(.9f * self.view.frame.size.width);
        pictFrame = CGRectMake(midPoint.x - imageWidth/2, midPoint.y - imageWidth/2, imageWidth, imageWidth);
        pictFrame.origin.y = self.view.frame.origin.y + .3f * pictFrame.origin.y;
    } else {
        CGFloat imageWidth = (unsigned int)(self.view.frame.size.height - 20 - 44);
        pictFrame = CGRectMake(midPoint.x - imageWidth/2, midPoint.y - imageWidth/2, imageWidth, imageWidth);
        pictFrame.origin.y = 10;
    }
    self.BGView = [[UIImageView alloc] initWithImage:imageToDisplay];
    self.BGView.frame = pictFrame;
    self.BGView.contentMode = UIViewContentModeScaleAspectFit;

    [self.view insertSubview:self.BGView atIndex:0];
}

The arithmetic is a little tricky, but basically I figure out how big the screen is, then subtract the menubar and bottom bar. Then fill 90% of whats left with the image. I use the scale factor, CGFloat scale = [UIScreen mainScreen].scale;, to make the device think that the image was created just for it, e.g. @2x or @3x.

Works in the simulator for all devices. I don’t have a new phone so I haven’t been able to test it on one yet.

This is what the background looks like.

enter image description here

JScarry
  • 1,507
  • 1
  • 13
  • 25
0

In your prefix.pch define the resolution :

    #endif
    #define   IsIphone6     ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )667 ) < DBL_EPSILON )
    #define   IsIphone5     ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
    #define   IsIphone4     ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )480 ) < DBL_EPSILON )
    #define   IsIphone6Plus     ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )736 ) < DBL_EPSILON )

in all your file .m now you can use if & else for any function:

  if (IsIphone6Plus) {

      bg.image = [UIImage imageNamed:@"bg6plus.png"];

  } else if (IsIphone6){

      bg.image = [UIImage imageNamed:@"bg6.png"];

  } else if (IsIphone5) {

      bg.image = [UIImage imageNamed:@"bg5.png"];

  } else if (IsIphone4) {

       bg.image = [UIImage imageNamed:@"bg4.png"];


  } else {

       bg.image = [UIImage imageNamed:@"ipad.png"];
  }

If for example the image is the same for 5/6 and 6plus you can use:

 if (IsIphone5||IsIphone6||IsIphone6Plus) {

          bg.image = [UIImage imageNamed:@"bg.png"];

      } else if (IsIphone4) {
           bg.image = [UIImage imageNamed:@"bg4.png"];
      } else {

           bg.image = [UIImage imageNamed:@"ipad.png"];
      }

This is valid for all example for a button position, dimensions of scroll views exc

hope this help you or other people

BlackSheep
  • 1,087
  • 12
  • 29