Adjust UILabel font size for device dimension - ios

Is there a way to set UILabel font to be greater in big device and smaller in small device?
Have I to do it programmatically, checking every time the device size?
My approach is this, now:
class func hightlightPtSize(height: CGFloat) -> CGFloat {
return height / 25
}
class func notSoHighlightPtSize(height: CGFloat) -> CGFloat {
return height / 30
}
class func stdPtSize(height: CGFloat) -> CGFloat {
return height / 35
}
class func sizeForType(height: CGFloat, type: Int) -> CGFloat {
switch type {
case STD:
return stdPtSize(height: height)
case HIGHLIGHT:
return hightlightPtSize(height: height)
case NOT_SO_HIGH:
return notSoHighlightPtSize(height: height)
default:
return 0
}
}

I have solution for your problem. Below my code in Objective C.
float newFontSize = [UIScreen mainScreen].bounds.size.height * (fontSize / 568.0);
if ([UIScreen mainScreen].bounds.size.height < 500) {
newFontSize = [UIScreen mainScreen].bounds.size.height * (fontSize / 480.0);
}
self.label.font = [UIFont fontWithName:self.label.font.fontName size:newFontSize];
I hope this helps you.

I tried before by making my default font for all labels larger than any possibility used - 60 in my case. Then set the adjustsFontSizeToFitWidth property to true to let the system size the font for me, while I set the size of my UILabel.
To make a label proportionate to the screen size you can use the autoresizing feature of storyboard. With the UILabel selected, if there is no existing constraints, you can see something like this:
In the right panel of Xcode, click the lines to toggle it on or off, the four line on the sides will tell if the view will maintain it's distance from the sides of it's superview the two in the square will tell if it resizes with it's superview in your case, make sure those are on as in the image above. As for the other four that I did not on, you can try experimenting toggling each on or off in combinations with others to find the exact behaviour you want.
If constraints are needed by it's siblings or super/sub views, I can suggest you try a set of constraints like:
Label(width) equal to SuperView(width) - change the multiplier to set how much of the space you want to take
Label(height) equal to SuperView(height) - same as width
Label(leading) equal to SuperView(leading) - change constant to set distance from leading edge, can change to trailing edge if needed
Label(Top) equal to SuperView(Top) same as leading, can change to bottom if needed.
It might be slightly verbose, but mainly take note of the first two to get the sizing, set the multiplier of the constraints not constant. The next two are mainly just to satisfy the requirements to properly place your label in the view. You can freely align centers or align top/bottom/leading/trailing in combinations to position it where you want.

My Swift version of kishan godhani's solution:
let screen = UIScreen.main
var newFontSize = screen.bounds.size.height * (defaultFont / 568.0);
if (screen.bounds.size.height < 500) {
newFontSize = screen.bounds.size.height * (defaultFont / 480.0);
}
label.font = label.font.withSize(newFontSize)

Related

How do I add constraints so that my view's dimensions do not change when the orientation changes?

I want my view to have the following properties (the numbers are arbitrarily chosen):
width is equal to height divided by 1.2
stays at the bottom right of the screen
height is 1/7 of the screen's height when in portrait
width and height does not change when the orientation changes
The first three requirements can be easily translated into UILayoutConstraints. I have done them with SnapKit just because it reads more clearly. You should see what I mean even if you have never used SnapKit before.
let myView = UIView(frame: .zero)
myView.backgroundColor = .green
view.addSubview(myView)
myView.snp.makeConstraints { (make) in
make.right.equalToSuperview().offset(-8)
make.bottom.equalToSuperview().offset(-8)
make.width.equalTo(myView.snp.height).dividedBy(1.2)
make.height.equalTo(view.snp.height).dividedBy(7) // *
}
The problem is the last bullet point. When I rotate the device from portrait to landscape, what was originally the width before the rotation, becomes the height after the rotation. This causes my view to become smaller as a result.
Basically, I want to replace the constraint marked with * with something like this:
make.height.equalTo(max(view.snp.height, view.snp.width)).dividedBy(7)
but I don't think max(a, b) is a thing in SnapKit or the UILayoutConstraint API.
Surely there is some other way of expressing "equal to whichever length is longer", right?
P.S. I didn't tag this with snapkit because I would also accept an answer that uses the UILayoutConstraint API.
Looks like you have 2 options:
Hardcode the height value.
Try to use nativeBounds:
This rectangle is based on the device in a portrait-up orientation. This value does not change as the device rotates.
In this case the height is always be for portrait mode.
myView.snp.makeConstraints { make in
make.right.bottom.equalToSuperview().offset(-8)
let screenHeight = UIScreen.main.nativeBounds.height / UIScreen.main.nativeScale
let height = screenHeight / 7
make.width.equalTo(height).dividedBy(1.2)
make.height.equalTo(height)
}

How to make text size relative to view in IOS?

In the XCode storyboard, I have set up my ViewController as a bunch of stackviews and everything is relative -- view dimensions are expressed as fractions of other view dimensions... lots of constraints, etc.
This is to make sure it looks decent on all IOS devices (phones and Ipads, anyway).
It does look acceptable in different aspect ratios, but I've noticed that the font size of my UILabels and TextViews are NOT changing -- not getting LARGER along with their containing views.
So, for example, if I switch from an iPhone to an iPad preview, a UILabel size may increase drastically and yet the text that it contains stays the same... so it's tiny text in a big box.
SO... the question is:
Is there a way to express font/text sizes as relative to the view that contains the text?
Something like this:
text.height = 0.7 * container.height
text.width = maintain aspect ratio with height
Thanks.
The same problem i had when i was designing an application for both iPhone and iPad and i tried this solution which is working fine but took a little efforts to manage. You need to create a custom label class which will inherits from UILabel class. There in your awakeFromNib function you can check the device and you can multiply whatever the font size with a ratio you feel ok for iPhone and iPad. You can also add checking for different iPhone sizes. If you wish to use different ratios for different label, make a IBDesignable property named dynamicRatio in your custom class and take that value to increase font. You can play around this. The effort is assigning the class to all your labels and setting properties which i use to do parallel during designing.
Below are the set of code which am using.
import UIKit
class MyLabel: UILabel {
#IBInspectable var autoFont: Bool = false
#IBInspectable var fontSize: CGFloat = 0
override open func awakeFromNib() {
super.awakeFromNib()
let baseHeight: CGFloat = (((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad)) ?1024.0:568.0)
if autoFont == true {
if (isDevice() == DEVICES.iPhoneX) {
let size: CGFloat = 667.0 * (fontSize / baseHeight)
self.font = UIFont(name: self.font!.fontName, size: size)
} else {
let size: CGFloat = UIScreen.main.bounds.size.height * (fontSize / baseHeight)
self.font = UIFont(name: self.font!.fontName, size: size)
}
}
}
}
Hope this idea helps.
Increase text font size of UILabels or UITextFields as you can, then set MinimumFontScale or MinimumFontSize attribute for them in "Attributes Inspector" tab, now font size increases as the UITextFields or UILabels size increases.
UILabel
UITextField

Get the intrinsic height of a custom control

How can I get the height of my custom control?
The idea is I will use it to dynamically set the height of some buttons inside the custom control. I've set the Placeholder height to 44 in the Xcode size inspector.
Working off Apple's Start Developing iOS Apps (Swift) tutorial, I am attempting to access frame.size.height and it gives a value of 1000 while the tutorial seems to suggest it should be 44.
class RatingControl: UIView {
...
override public var intrinsicContentSize: CGSize {
let buttonSize = Int(frame.size.height)
print(buttonSize) // prints 1000
let width = (buttonSize * starCount) + (spacing * (starCount - 1))
return CGSize(width: width, height: buttonSize)
}
...
You should never access frame inside intrinsicContentSize. intrinsicContentSize should return the size that perfectly fits the contents of the view, regardless of its current frame.
In your case, I think you can just use 44 for your buttonSize.
The placeholder intrinsic size is just that, placeholder, so that IB interpreter is has some value to work with and can layout the rest of the scene. But in your intrinsicContentSize getter, you implement the real size, which will be used in runtime by the AutoLayout engine. Since you return 1000 as the intrinsic content height, that's what you will see in runtime.

Scale text label by screen size

Is there a way to scale text so that it takes up close to the same screen real estate no matter what the device size is? I've found that the text on an iPad sized device is too small in relation to the screen size when compared to the iPhone. Below is an example of what I'm looking for. Notice the text percentage size is similar in relation to the device screen size.
Example
To set constraints on the label that you have, see this link: How do you make a background image scale to screen size in swift? . I know that you might not be using Swift (I'm using Objective-C), but the first answer shows how to do it in the storyboard. Do the same thing it says, but for the label. Then, see the image below to change the auto shrink options for the label from "Fixed Font Size" to "Minimum Font Scale" (see image below). Hope this helps!
1. Select your label and open attribute inspector for it
2. Click on + sign by Font, select width and height as "Regular", click Add Variation
3. Another Font field will appear, this will represent font for ipad/big screen/ illusion of big screen (scroll view)
4. Select your desired font for ipad
I had my own fix and it's not one click, but I found it well worth it.
Step 1:
Test some font sizes for different screen sizes, recording the font size and the most relevant other dimension.
Here's what I mean...
I'd start with a normal iPad Screen and select a font size that worked.
Since I knew the entire height of the screen would determine what makes a font size comfortable or not, I'd record the font size along with the entire screen height.
So the font size was 50 with a height of 1024.
Then, I switched to the iPhone SE
This was pretty atrocious, so I fixed the font size:
After recording that the font size worked at 25 with a height of 568.
Step 2:
Bust out the calculator app and find a constant that relates the font sizes to the heights (in my case), giving or taking a bit.
Here's what I mean:
I knew 50 works with 1024 and that 25 works with 568.
Dividing 50/1024 gives you .048828125.
Multiplying that by 568 equals 27.734375, which would be a little fat of a font size for the SE.
Repeating that process but using the SE's values to do the division produced .0440140845, and checking that with the iPad's height produces a font size of 45, just a bit small for the mighty iPad screen.
So I split the quotients down the middle, resulting in a number around 0.46.
Step 3:
Connect the labels and change their font sizes programmatically using this number.
First, drag the labels into an outlet collection. I named my connection 'headerLabels' since they're all at the top of the screen.
Then, you can kinda steal my code, but just don't make too much money with it ;)
// Outlet collection of labels
#IBOutlet var headerLabels: [UILabel]!
// Who needs a short variable name when we can have a
// painfully lengthy one to describe the number we calculated?
let relativeFontConstant:CGFloat = 0.046
override func viewDidLoad() {
super.viewDidLoad()
// Should be in the viewDidLoad so it can load the same time as
// the view does.
// apply a font size to all the labels.
for label in headerLabels {
// multiply the height we based it on of the entire view
// to the number we calculated
label.font = label.font.withSize(self.view.frame.height * relativeFontConstant)
}
}
If you've got any questions, comments, compliments, or insults let me know :)
I was having the same issue where I needed the text to be scaled proportionally along with the screen size increase.
Adaptive sizing is quite limited as you can only set the font sizing for size classes. Having the font sizes for two width options, compact and regular was not a solution for me.
I have written a small lib which handles automatic font scaling for UILabel and UITextView for different screen sizes.
You can set the scaling globally or for a specific instance of UILabel and UITextView.
Find it here: AMXFontAutoScale
I had decent behavior with the following code in my viewDidLoad function:
(Note that the screen bounds are in 'points' not 'pixels')
// Set the clock font size according to the height.
// Design was done on iPhone XR with height of 896 points and font size of 98.
if (UIScreen.main.bounds.height != 896). // Only need code if not on original design size.
{
let scaleFactor: Float = Float(UIScreen.main.bounds.height) / 896.0
let fontSize = CGFloat(98.0 * scaleFactor)
self.clock.font = self.clock.font.withSize(fontSize)
}
This was using the "Helvetica Neue" font which is a fixed width font. It wasn't completely scaled up completely for some reason on larger devices, so still a bit smaller than the target on iPads, but close enough.
different screen sizes acoording to
// iphone 5s,SE screen width 320
// iphone 6,6s,7,etc width 375
// iphone 7 plus, 8 plus, xs max,etc width 414
if (self.view.frame.width == 320) {
label.font = UIFont(name: label.font.fontName, size: 16)
} else if (self.view.frame.width == 375) {
label.font = UIFont(name: label.font.fontName, size: 21)
} else if (self.view.frame.width == 414) {
label.font = UIFont(name: label.font.fontName, size: 24)
}
There is an aspect ratio constraint available. Add this to your label. Constraints to left and top margins for anchoring the label in place should silence the compiler warnings.
As #VatsalManot mentioned, learn adaptive sizing for starters. Here's a good link:
http://www.raywenderlich.com/83276/beginning-adaptive-layout-tutorial
Hope this helps! :)
for those who want more than xCode editor has to offer this is my hack and its not future proof,
based on this post we can scale font programmatically
Warning!! SCALE FACTOR is not refined yet.
you will need to work on it.
usage:
titleView.font = UIFont.appFont(ofSize: 24, weight: .bold)
contentView.font = UIFont.appFont(ofSize: 16)
code:
extension UIFont {
class func appFont(
ofSize size : CGFloat = UIFont.systemFontSize,
weight : Weight = .regular,
autoScale : Bool = true
) -> UIFont {
return UIFont.systemFont(ofSize: autoScale ? size.dp : size, weight: weight)
}
}
extension CGFloat {
var dp: CGFloat {
let width = UIScreen.main.bounds.width
let device = UIScreen.main.traitCollection.userInterfaceIdiom
if (device == .phone) {
if (width <= 320) {
// iPod(Gen7)
// iPhone(5s, SEGen1)
return self * 0.75
} else if (width <= 375) {
// iPhone(SEGen2 6, 6s, 7, 8, X, Xs, 11pro, 12mini, 13mini)
return self * 0.95
} else if (width <= 414) {
// iPhone(6+, 6s+, 7+, 8+, XsMax, XR, 11, 11proMax, 12, 12pro, 13, 13pro)
return self
} else if (width <= 744) {
// iPhone(12proMax, 13proMax)
return self * 1.2
}
} else if (device == .pad) {
if (width <= 744) {
// ipad(miniGen6, )
return self * 1.4
} else if (width <= 768) {
// ipad(Gen5, Gen6, Air, Air2, Pro9.7)
return self * 1.45
} else if (width <= 810) {
// ipad(Gen9)
return self * 1.5
} else if (width <= 834) {
// ipad(AirGen3, AirGen5, Pro10.5, Pro11Gen1, Pro11Gen3)
return self * 1.55
} else if (width <= 1024) {
// ipad(Pro12.9Gen1, Pro12.9Gen2, Pro12.9Gen3, Pro12.9Gen5)
return self * 1.85
}
}
return self
}
}

iPhone - resizing image and two labels to fit the screen

I'm new to iPhone developing. I have a screen with image, title and content:
Image has dynamic size and also all text can have any length. What I want to achievie is to fit the image exactly in screen and make all labels to be only as long as they should be.
Afterk about 5 hours of work I have:
Working labels length, achieved by setting Lines=0 and Preferred Width=content width
Not working image, which lefts blank spaces
I have read a lot, I understand Content Hugging Priority and Content Compression Resistance Priority. I know differences in UIViewContentMode. I know that I can manually set UIImage.frame=CGRectMake(...). Nothing works. My image is more wider than higher (lets assume that width/height = 3). If I have UIViewContentMode=Aspect Fit then I will have blank space above and below the image. If set to Aspect fill then image is too high and also cropped. Changing frame in code doesn't change anything in view. What I want is to have image with size that was made using Aspect fit, but without blank space.
Finally I dit it. First of all, everyone writes that UIImageView.Frame should be modified to shrink the image, but be aware, that if your view is UITableViewCell then you should do that in layoutSubviews method (remember to invoke super.layoutSubviews() at the begging).
Secondly, make in IB a height constraint for your UIImageView for temporary value (for example 100). You will change that constraint in layoutSubviews method.
And finally: fitting image is NOT about its ratio. Set UIViewContentMode=Aspect Fit. Then the case with blank top and bottom areas occurs only when the initial image is wider than screen. Calculating the proper height should also take place in layoutSubviews.
Example implementation:
override func layoutSubviews() {
super.layoutSubviews()
var imageWidth = (imageViewObject.image?.size.width)!
var imageHeight = (imageViewObject.image?.size.height)!
var frameWidth = UIScreen.mainScreen().bounds.width
var properHeight: CGFloat
if imageWidth > frameWidth {
var ratio = frameWidth / imageWidth
properHeight = imageHeight * ratio
}
else {
properHeight = imageHeight
}
imageHeightConstraint.constant = properHeight
imageViewObject.frame = CGRectMake(0, 0, frameWidth, properHeight)
}

Resources