I'm developing swift based iOS application for iPhone family. My application supports all devices start from iPhone 4s to iPhone X. Labels appears bigger in smaller devices like iPhone 4s as I added bigger font size for high end devices. Can someone help me on how to scale the font according to device. I tried size classes with compact/regular width and compact/regular height but none of them helped me. Your help is very much appreciated
Programmatically
Without using the storyboard I have the approach to simply change the font size depending on the screen width like so:
func dynamicFontSize(_ FontSize: CGFloat) -> CGFloat {
let screenWidth = UIScreen.main.bounds.size.width
let calculatedFontSize = screenWidth / 375 * FontSize
return calculatedFontSize
}
and can be used as:
myLabel.font = UIFont(name: "Helvetica", size: dynamicFontSize(20))
Note that in the dynamicFontSize function the number 375 is simply the basis for the font size calculation, because I usually test my app on iPhone 8 (i.e. font size 18 is actually 18 on an iPhone 8 due to its actual width of 375). This number can be altered to your liking.
Storyboard
If you insist on using storyboard, you can instead create a new swift file subclassing UILabel and use an #IBInspectable like so:
import UIKit
class UILabelFontClass: UILabel {
#IBInspectable var DynamicFontSize: CGFloat = 0 {
didSet {
overrideFontSize(FontSize: DynamicFontSize)
}
}
func overrideFontSize(FontSize: CGFloat){
let fontName = self.font.fontName
let screenWidth = UIScreen.main.bounds.size.width
let calculatedFontSize = screenWidth / 375 * FontSize
self.font = UIFont(name: fontName, size: calculatedFontSize)
}
}
Inside storyboard subclass UILabelFontClass to your label:
And now in the Attributes inspector, you can set the font size:
You can try label hight according to view in storyboard .
with this image reference i done with iPhone 5s screen size and give label hight equal to hight in multiplier 30/554
Instead of making different class for UILabel. You can make UILabel Extension and use this IBDesignable Solution to set values from Storyboard.
Here Base width is 375pt
extension UILabel{
#IBInspectable
var scaleSize: CGFloat {
set {
let fontName = self.font.fontName
let screenWidth = UIScreen.main.bounds.size.width
let calculatedFontSize = screenWidth / 375 * newValue
self.font = UIFont(name: fontName, size: calculatedFontSize)
}
get {
return self.scaleSize
}
}
}
Related
I have been reading through the various options on how to set the vertical alignment on an NSTextField. I want the text to be displayed in the center and to do it programatically in Swift. Here are the things I have looked so far:
http://www.cocoabuilder.com/archive/cocoa/174994-repositioning-an-nstextfieldcell.html
https://red-sweater.com/blog/148/what-a-difference-a-cell-makes
Vertically Centre Text in NSSecureTextField with subclassing
Get NSTextField contents to scale
vertically align text in a CATextLayer?
One thing I have tried in Swift is to set the following property:
textField.usesSingleLineMode = true
Any tips on the best way to vertically center text would be much appreciated!
This is very hard to do, as Apple makes this very difficult. I achieved it by subclassing NSTextFieldCell and overriding the drawingRectForBounds: method like so:
override func drawingRectForBounds(theRect: NSRect) -> NSRect {
let newRect = NSRect(x: 0, y: (theRect.size.height - 22) / 2, width: theRect.size.width, height: 22)
return super.drawingRectForBounds(newRect)
}
This is just my way to do it, I'm sure there are better ways, which I don't know (yet). And this only works for the standard font size in TextFields (which gives a text height of 22). That's why I hardcoded that. Haven't figured out yet, how to get the height in the cell if you change the font.
Result:
Try this on a playground, it centers the text perfectly, use it on your projects! Hope it helps!
import Cocoa
let cell = NSTableCellView()
cell.frame = NSRect(x: 0, y: 0, width: 100, height: 100)
let tf = NSTextField()
tf.frame = cell.frame
tf.stringValue = "MyTextfield"
tf.alignment = .Center
let stringHeight: CGFloat = tf.attributedStringValue.size().height
let frame = tf.frame
var titleRect: NSRect = tf.cell!.titleRectForBounds(frame)
titleRect.size.height = stringHeight + ( stringHeight - (tf.font!.ascender + tf.font!.descender ) )
titleRect.origin.y = frame.size.height / 2 - tf.lastBaselineOffsetFromBottom - tf.font!.xHeight / 2
tf.frame = titleRect
cell.addSubview(tf)
I have added the NSTextField inside a NSView and centered it.
Another solution was (in an iOS project) to create a UILabel and allow it adjust its size (sizeToFit()) and again embed it inside a UIView.
I personally don't like the calculations in previous answers and the second solution for iOS works for all texts size and row numbers.
I was also facing vertical alignment issue with NSTextField. My requirement involved, rendering a single-line string inside a NSTextField. Additionally,
textfield needed to be resize implying we had programatically resized the font-point-size of the text inside text-field on resize. In this scenario we faced vertical-alignment issues - the mis-alignment was tough to grasp/understand in a straight forward way.
What finally worked:
So, in my scenario a simple,
turn off the "Single Line Mode" in interface builder
for the text-field solved the issue.
The accepted answer works perfectly and here's the Swift3 version.
class VerticallyAlignedTextFieldCell: NSTextFieldCell {
override func drawingRect(forBounds rect: NSRect) -> NSRect {
let newRect = NSRect(x: 0, y: (rect.size.height - 22) / 2, width: rect.size.width, height: 22)
return super.drawingRect(forBounds: newRect)
}
}
This question already has an answer here:
images render larger when loaded programmatically on iPhone X,Xs?
(1 answer)
Closed 1 year ago.
I have an ImageView on my Storyboard layout and I put some images over this ImageView.
To maintain the proportion of the image I created a code to calculate the image scale.
static func getImageScale(_ myImage:UIImageView) -> (width: CGFloat, height: CGFloat) {
let imageViewHeight = myImage.bounds.height
let imageViewWidth = myImage.bounds.width
let imageSize = myImage.image!.size
let myScaledImageHeight = imageViewHeight / imageSize.height
let myScaledImageWidth = imageViewWidth / imageSize.width
return (width: myScaledImageWidth, height: myScaledImageHeight)
}
This is how I use the code above:
ImageMarcasHelper.addScaledImageToScreenWithoutMovement(imageStringName: nome_imagem, scaledImageWidth: percentImageScale.width, scaledImageHeigth: percentImageScale.height, view: view)
Finally, I call this:
static func addScaledImageToScreenWithoutMovement(imageStringName imageNameString:String, scaledImageWidth:CGFloat, scaledImageHeigth:CGFloat, view:UIView) {
var xFinal = 0
var scaledImageWidthMultiplied:CGFloat = 0.0
let vc: UIViewController = view.parentViewController!
let vc_name = type(of: vc)
let image = UIImage(named: imageNameString)
print(image!)
let imageView = UIImageView(image: image!)
imageView.isAccessibilityElement = true
imageView.restorationIdentifier = imageNameString
if vc_name == ResenhaMarcasCabecaController.classForCoder() ||
vc_name == ResenhaMarcasMembrosPosterioresController.classForCoder() {
print("ResenhaMarcasCabecaController view used")
xFinal = Int((image?.size.width)!/1.9)
scaledImageWidthMultiplied = (image?.size.width)! * 1
} else {
// identifica todas as outras views como ResenhaMarcasFocinhoController ou ResenhaMarcasPescocoController ou ResenhaMarcasMembrosAnterioresController
print("viewcontroller genenrica usada")
xFinal = 0
scaledImageWidthMultiplied = (image?.size.width)! * scaledImageWidth
}
imageView.frame = CGRect(
x: xFinal,
y: 0,
width: Int( scaledImageWidthMultiplied ),
height: Int( (image?.size.height)! * scaledImageHeigth )
)
view.addSubview(imageView)
}
On some iPhone models the image resize works perfectly, but on other models it is not calculated correctly.
Check below the images from an iPhone 8 and an iPhone 8 Plus
The red image on the left side is centered, but on the right side the red image is NOT centered.
How can I fix that? There is another code that can I use to fix it or do I need to adapt something on my code?
Or maybe another solution, there is any way to detect the type of screen size or dimension? The same problem happens with iPhone 11 Max and iPhone Max Pro.
The red image is centered on iPhone 11 Max, but is NOT centered on iPhone Max Pro.
--- EDIT ---
#IBOutlet weak var imagemPrincipalCabeca:UIImageView!
I have an IBOutlet that contains the ImageView that I created using Storyboard with AutoLayout and I use the image inside this ImageView to get the scale to apply to other images.
This is the code that I use to get and apply the scale from the IBOutlet that is assigned to the ImageView
let percentImageScale = ImageMarcasHelper.getImageScale(imagemPrincipalCabeca)
ImageMarcasHelper.addScaledImageToScreenWithoutMovement(
imageStringName: nome_imagem,
scaledImageWidth: percentImageScale.width,
scaledImageHeigth: percentImageScale.height,
view: view)
I find out what is the problem.
All calculations are done inside the "viewDidLoad" method. Inside this method, the calculations are not correct because the view still does't know the correct size of the subviews(the container view)
I change all the calculations to be made inside the "viewWillAppear" method. This way I was able to get the correct screen width and height for the subview.
I have designed a screen using Storyboard constraints for iPhone XR, but that design become big in iPhone7, so I want to change the height and width of my ContainerView using NSLayoutConstraints.
I have taken:
#IBOutlet weak var containerViewheight: NSLayoutConstraint!
This ContainerView actual height in iPhoneXR is 300, so I want to change it in iPhone7
For example:
if (iphone7) {
self.containerViewheight.constant = 240
}
if (iphone SE) {
self.containerViewheight.constant = 280
}
Unfortunately I have very little knowledge in size classes.
You can always ask the UIScreen class method main for the current concrete size, it returns the concrete size of the current device.
let deviceSize = UIScreen.main.bounds.size
But you probably know, that height and width change depending on the orientation the device has (landscape or portrait).
Maybe this extension could help:
import UIKit
extension UIScreen {
/// Retrieve the (small) width from portrait mode
static var portraitWidth : CGFloat { return min(UIScreen.main.bounds.width, UIScreen.main.bounds.size.height) }
/// Retrieve the (big) height from portrait mode
static var portraitHeight : CGFloat { return max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) }
/// Retrieve the (big) width from landscape mode
static var landscapeWidth : CGFloat { return max(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) }
/// Retrieve the (small) height from landscape mode
static var landscapeHeight : CGFloat { return min(UIScreen.main.bounds.size.width, UIScreen.main.bounds.size.height) }
}
You can manipulate by knowing what ratio you want your container height to be of the screen height.
For eg: if UIScreen.main.bounds.height gives you 1000. And your appropriate container height here is 400. Then the required ratio of height of container to height of screen is 400/1000 or 2/5.
Now, what you can do is write
containerViewheight.constant = (2/5)*UIScreen.main.bounds.height
I have a UICollectionView with cells sized to the same aspect ratio as a4 page. And with different screen sizes I would like for that text to be sized at fixed 12pt (that would be calculated to that UICollectionview cell), which would look bigger on the iPad and smaller on iPhone.
So having a fixed font size isn't an option...
Coding
var fontSize : CGFloat = 12.0 // DEFAULT SIZE
In your ViewDidLoad
if UIDevice().userInterfaceIdiom == .phone {
switch self.view.frame.size.height {
case 480:
fontSize = 12.0
case 568:
fontSize = 14.0
case 667:
fontSize = 16.0
case 736:
fontSize = 17.0
case 812:
fontSize = 18.0
default:
print("unknown")
}
}
else if UIDevice().userInterfaceIdiom == .pad {
fontSize = 20.0
}
Then apply this fontSize, wherever u need.
Storyboard
Select UITextView, in Attributes Inspector area, + (plus) symbol is near to Font. By default it will work for iPhone devices. For iPad, Change change size classes to Regular width and Regular Height wR hR . For, that U can increase font size.
I am working on an iOS app and I observed the UI in iPhone 5,6,6+ all fonts are different device by device, but my requirement is button sizes and font sizes must be same for iPhone4s,5 and different for iPhone 6 and 6+.How can I achieve this in my app. I know we can do by programmatically, but is there any chance to do on storyboard using adaptive layouts.
I am using xcode7.2, swift2.
Thanks in advance..
I was facing the same problem and solved it using Swifts Computed Properties.
I created a static variable fontsize which gets dynamically initialized with the appropriate fontsize due to the size of the screen.
import UIKit
class ViewFunctions {
let screenSize = UIScreen.mainScreen().bounds.size
static var fontsize: CGFloat {
get {
if screenSize.height >= 1024 { // iPad Pro
return 16.0
} else if screenSize.height >= 768 { // iPad
return 16.0
} else if screenSize.height >= 414 { // iPhone 6Plus
return 15.0
} else if screenSize.height >= 375 { // iPhone 6/s
return 15.0
} else if screenSize.height >= 320 { // iPhone 5/s
return 14.0
} else if screenSize.height >= 319 { // iPhone 4/s
return 14.0
} else {
return 14.0
}
}
}
}
Then use it for example to set the fontsize of a button-label:
import UIKit
class TestClass {
var testButton: UIButton = UIButton(type: UIButtonType.System) as UIButton!
testButton.titleLabel!.font = UIFont(name: "Helvetica Neue", size: ViewFunctions.fontsize)
testButton.setTitle("Test", forState: .Normal)
// add button to view or sth like that...
}