19

How to uniquely identify iPhone 6 and iPhone 6 plus portrait screens using size classes?

My App looks good in iPhone 4 and iPhone 5 but the same looks with lots of empty spaces in iPhone 6 and 6 plus because of screen sizes. Though am using auto layout i can't increase the font size or view size only for iPhone 6 and 6 plus alone. I knew that we can change the font size and view size using size classes. but in my case don't know what to do.

Am using xCode 6.1 and my app supports from iOS 7 to latest iOS 8.1. Am expecting solution only in storyboards as am doing my UI designs fully in storyboard. If storyboard has limited functionality to achieve my needs please let me know how to achieve the same with code through out the app?

Bluewings
  • 3,245
  • 3
  • 16
  • 31
  • It's all the same as far as size classes and device type are concerned. If you are doing auto layout correctly, view size will just change as the screen's proportions change. Can you show screen shots of why you need a different font size? – matt Nov 21 '14 at 16:31
  • @matt you can see the file here for iPhone 6 plus. Due to NDA i cant share the real version. I just need gaps between each label and i do have some controls down . https://www.dropbox.com/s/ycar93s6j8djv33/Screen%20Shot%202014-11-22%20at%2012.51.44%20AM.png?dl=0 – Bluewings Nov 21 '14 at 16:56
  • Thanks for the screen shot but what is it that you think is wrong with it? – matt Nov 21 '14 at 17:02
  • @matt the requirement is to have same layout for all the screen sizes. So if the screen size increases then automatically my label size and label to text field gap needs to be increased. :( As of now the size is same as lower sizes. – Bluewings Nov 21 '14 at 17:03
  • 1
    "the requirement is to have same layout for all the screen sizes" That's a dumb "requirement". The whole philosophy here is to _adapt_ to the changing multiple screen sizes. That's why the WWDC videos on this topic are about _adapting_. Saying "the same layout" is the opposite of adapting. It is _stodgy_. :) If you don't want to adapt, then heck, include only a launch image for iPhone 4s and let yourself be zoomed up on the iPhone 6 models. You'll have _exactly_ the same interface then. – matt Nov 21 '14 at 17:54
  • i knew it is the dumb requirement but my dumbest designer want that way :( between could you please elaborate more on the zooming up for iPhone 6 models. Or Can i go ahead and use diffent storyboard for iPhone 6 models alone? – Bluewings Nov 22 '14 at 06:50

10 Answers10

24

Another option to adjust the font size according to the iPhone type, is to use 'User Defined Runtime Attributes'.

Define an extension to UILabel:

extension UILabel {
    var adjustFontToRealIPhoneSize: Bool {
        set {
            if newValue {
                var currentFont = self.font
                var sizeScale: CGFloat = 1
                let model = UIDevice.CurrentDevice().modelName()

                if model == "iPhone 6" {
                    sizeScale = 1.3
                }
                else if model == "iPhone 6 Plus" {
                    sizeScale = 1.5
                }

                self.font = currentFont.fontWithSize(currentFont.pointSize * sizeScale)
            }
        }

        get {
            return false
        }
    }
}

In order to determine the current model name, please refer to the following answer: https://stackoverflow.com/a/26962452/4165128

On the storyboard, select the label you wish to adjust, open the right pane, select the identity inspector, and add the 'adjustFontToRealIPhoneSize' property to the list of user defined runtime attributes (with type 'Boolean' and checkbox checked).

Do the same for each label you wish to adjust (copy & paste surprisingly works here).

Community
  • 1
  • 1
Alonzo
  • 693
  • 5
  • 12
  • 5
    You could add a @IBInspectable to that extension and then you can edit it directly from the Attributes Inspector. – Fábio Oliveira Feb 06 '15 at 09:23
  • Can somebody provide its Objective-C Version? – Bista Sep 03 '15 at 10:52
  • 1
    I don't think nailing exact models is the (even intended) way to go with for targeting multi size devices. – Jonny Aug 22 '16 at 02:36
  • String comparing to model names is not a good idea idea (to put it nicely). You should use size classes. Check for the size class in various dimensions to determine what size font to use. See my answer for an example. – Michael Peterson Dec 01 '16 at 13:16
8

Use Compact width and Regular Height in storyboard

Use Compact width and Regular Height in storyboard

Add layout constraint of hight and width relative with super view by adding multiplier. Let's say you have image view which has size half the super view then add multiplier 0.5.

enter image description here

Jignesh Agola
  • 320
  • 1
  • 11
  • Could you please explain little bit more on multiplier or give some link to read about it please? – Bluewings Nov 21 '14 at 16:35
  • As of now i have set the size class as you mentioned in the image. But for iPhone 6 plus my font looks too small. – Bluewings Nov 21 '14 at 16:36
  • but my issues is with the font size and gap between other controls. Say i have a label and text field with a gap of 10. it looks good in smaller screens but in biggers screen it will like same so i can see lots of empty spaces. Is there any way to identify and change the font size and gap between controls? – Bluewings Nov 21 '14 at 16:47
  • thanks for the answer. i have added a screen shot to the comments for my question. please see to it to understand my needs. – Bluewings Nov 21 '14 at 17:09
  • Helped me out. Thanks! – NightFury Jun 30 '15 at 05:41
  • Both the iPhone 6 and 6 Plus use Regular Height when in portrait mode so this will not differentiate between the these two devices. See https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/MobileHIG/LayoutandAppearance.html – Michael Peterson Sep 08 '15 at 16:06
  • @Jignesh - It works for me but partially. The image size decreases but how to manage the spacing between each image? How to reduce the spacing? Please let me know – Lohith Korupolu Jun 02 '16 at 16:00
2

Check out adjustsFontSizeToFitWidth @ UILabel Class Reference. This will allow you to do some nice adjustments based on the different devices.

label.adjustsFontSizeToFitWidth = YES;
Mark McCorkle
  • 9,206
  • 2
  • 30
  • 42
2

I don't have too much idea of sizeClass for different font size in different iPhone devices but I figured out with this solution.

  1. Add this method to your utility class.
  2. Just pass your super view to this method, this method is recursive so if you pass self.view than all subviews are set.
  3. Change your font size as you need.
-(void)setAllFonts:(UIView *)view
{

CGFloat fontSizeDiff = 0.0;

if (IS_IPHONE_6)
{
    fontSizeDiff = 1;
}
else if (IS_IPHONE_6PLUS)
{
    fontSizeDiff = 2;
}

for (UIView *vw in [view subviews])
{
    if ([vw isKindOfClass:[UILabel class]] || [vw isKindOfClass:[UIButton class]])
    {
        if ([vw isKindOfClass:[UILabel class]])
        {
            UIFont *font = [(UILabel *)vw font];
            [(UILabel *)vw setFont:[UIFont fontWithName:font.fontName size:font.pointSize+fontSizeDiff]];
        }
        else
        {
            UIFont *font = [(UIButton *)vw titleLabel].font;
            [(UIButton *)vw titleLabel].font = [UIFont fontWithName:font.fontName size:font.pointSize+fontSizeDiff];
        }
    }
    else if ([vw isKindOfClass:[UIView class]] || [vw isKindOfClass:[UIScrollView class]])
    {
        [self setAllFonts:vw];
    }
}
}
iBhavik
  • 667
  • 10
  • 28
  • "I don't have too much idea of sizeClass for different font size in different iPhone devices" ... this is where you should STOP, and learn how to use size classes instead of putting in a hack. How does this code handle iPhone 7, 8, iPad Pro, etc...? – Michael Peterson Dec 01 '16 at 13:30
2

Swift Version of @iBhaviks answer :

func getFontScaleForDevice() -> CGFloat {
    var sizeScale = CGFloat(1.0)
    if DeviceType.IS_IPHONE_6 {
        sizeScale = 1.2
    } else if DeviceType.IS_IPHONE_6P {
        sizeScale = 1.4
    } else if DeviceType.IS_IPAD {
        sizeScale = 1.4
    }
    return sizeScale
}

func setAllFonts(targetView:UIView, scale:CGFloat) {
    for vw in targetView.subviews {
        if let vl = vw as? UILabel {
            vl.font = vl.font.fontWithSize(round(vl.font.pointSize * scale))
        } else if let vb = vw as? UIButton, vbl = vb.titleLabel {
            vbl.font = vbl.font.fontWithSize(vbl.font.pointSize * scale)
        } else if vw.subviews.count > 0 {
            setAllFonts(vw, scale: scale)
        }
    }
}

override func viewDidLoad() {
    super.viewDidLoad()
    let sizeScale = getFontScaleForDevice()
    if sizeScale > CGFloat(1.0) {
        setAllFonts(view, scale: sizeScale)
    }
    view.layoutIfNeeded()
}
ergunkocak
  • 2,938
  • 1
  • 26
  • 27
  • Please don't encourage comparison to specific models. This code will break within a year. Learn to properly use size classes like Apple intended. – Michael Peterson Dec 01 '16 at 13:27
1

Maybe you could set the perfect font size for the big screens, and then set the Autoshrink to minimum font size with the perfect size for the small screens, in that way you can have a dynamic font size without coding.

You will have to set the constraints for the label to adjust its size with the screen size anyway.

Hope this help

1

After struggling lot just found of something for my need so posting the same for the future readers.

  1. As of now there is no way to uniquely identify the iPhone 6 model portraits using Size classes. However you can use compact width and regular height to design for all iPhones portrait screens
  2. To change font size you have to identify which iPhone the app currently running on using code and set the font size based on the same
  3. For my requirement - same layout for all the screen sizes - use multiplier in widths and heights constrains. Check Jignesh answers for this question to know more about it.

EDIT 24-SEP-2015 I recently found a way to customize your size class by using UITraitColleection only for iPhone 6 plus so you don't need to write much of code. i hope this link will help someone in future.

Bluewings
  • 3,245
  • 3
  • 16
  • 31
  • But if we also want to support landscape mode for iPhones, the way using `UITraitColleection` wouldn't help. – nickcheng Jun 17 '16 at 06:45
1

Bit late to this but I needed a label that would scale up to any device and used this method.

Create a new subclass of UILabel and in the .h file put this…

#import <UIKit/UIKit.h>

IB_DESIGNABLE

@interface OTHD_ScalableLabel : UILabel

@property (nonatomic, assign) IBInspectable CGFloat fontScale;

@end

and in the .m file put this…

#import "OTHD_ScalableLabel.h"

@implementation OTHD_ScalableLabel

- (void) layoutSubviews
{
    [super layoutSubviews];

    if( self.fontScale < 0.1 || self.fontScale > 1.0 )      self.fontScale = 1.0;

    CGFloat height = CGRectGetHeight(self.bounds) * self.fontScale;

    if( height )        self.font = [UIFont fontWithName:self.font.fontName size:height];
}


@end

You can then just change your class in IB and using IBInspectable you will be able to scale the label up or down. Obviously, for the pedantics out there, this is not a good idea for general use but there are some cases where you might need, for example, a large label that displays full screen on an iPhone as well as full screen on an iPad.

amergin
  • 2,926
  • 28
  • 41
1

Here is an example of a function that I use to toggle between two different font size at runtime. It decides which font to use based on the horizontal size class - which essentially splits devices into two groups "iPad" and "iPhone". Here is a good refernce on whch devices belong to which size classes: http://useyourloaf.com/blog/size-classes/

  • iPad and Up
  • iPhone Plus and Down
 func chooseFont(compactFont: UIFont, regularFont: UIFont) -> UIFont {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    return appDelegate.window!.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.compact ? compactFont : regularFont
}
Bluewings
  • 3,245
  • 3
  • 16
  • 31
Michael Peterson
  • 9,046
  • 3
  • 51
  • 48
0

Based on your screen shot I would suggest using Dynamic Type. That way the user is in charge of the size of the text.

matt
  • 447,615
  • 74
  • 748
  • 977
  • So you meant to say as a developer i don't need to care about the font size and gap between controls. So my app will look with lots of gaps in bigger screens and definitely it will affect the user experience. – Bluewings Nov 21 '14 at 17:07
  • Why should there be "lots of gaps"? That is what auto layout takes care of. – matt Nov 21 '14 at 17:52