UITextView font to always be fixed size - swift

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.

Related

Autoshrink fontsize of UILabeltext siwft

I have a multiline UILabel text which expands dynamically according to the text length. I have setup proper auto layout in storyboard and grows bigger if the text is lengthy.
But i want to reduce the font size to 24 if its 2-line and to 20 if its 3-line text.
If text is single line then, font size should be 34.
I tried minimum font scale = 20/34 = .58
but no use. Please suggest a solution
You could use a switch statement to determine the font size when a certain number of lines have been after changing the label's text.
Using the actualNumberOfLines() algorithm from https://stackoverflow.com/a/60993649/12783209 allows you to redeclare the font for this label whenever necessary.
func changeFontSizeIfNeeded(on label: inout UILabel){
switch label.actualNumberOfLines{
case 2:
label.font = label.font.withSize(24)
case 3:
label.font = label.font.withSize(20)
default:
//Change this to be the default font size
label.font = label.font.withSize(30)
}
}
And add this extension to your project:
extension UILabel{
func actualNumberOfLines()-> Int {
// You have to call layoutIfNeeded() if you are using autoLayout
self.layoutIfNeeded()
let myText = self.text! as NSString
let rect = CGSize(width: self.bounds.width, height: CGFloat.greatestFiniteMagnitude)
let labelSize = myText.boundingRect(with: rect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: self.font as Any], context: nil)
return Int(ceil(CGFloat(labelSize.height) / self.font.lineHeight))
}
}

How to change design according to screen size using NSLayoutConstraint in swift

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

Swift UIButton Title Text: Rotation is causing issues with text sizing

I am working on an MTG life counter app and am having issues with UIButtons and their title text not sizing properly after rotating for a vertical view. The text either comes out very small when I set the font size to adjust to fit width, or as "..." when I don't set the font size to adjust to fit the width.
https://imgur.com/a/BEI3Zim
I have tried to set the font to adjust to fit width, but then it comes out very small and unreadable. If I don't set the font to adjust to fit width, then the text comes out as "..."
// player 3 cell
let cell = tableView.dequeueReusableCell(withIdentifier: "VerticalPlayerTableViewCell", for: indexPath) as! VerticalPlayerTableViewCell
cell.player.name = playerData[2].name
cell.player.health = playerData[2].health
cell.playerTopButton.backgroundColor = playerData[2].playerColor
cell.playerTopButton.setTitle(String(cell.player.health), for: .normal)
cell.playerBottomButton.backgroundColor = playerData[2].playerColor
cell.playerBottomButton.setTitle(cell.player.name, for: .normal)
// rotating top button title text
cell.playerTopButton.titleLabel?.transform = CGAffineTransform(rotationAngle: (CGFloat.pi / 2) )
cell.playerTopButton.titleLabel!.adjustsFontSizeToFitWidth = true
cell.playerTopButton.titleLabel!.numberOfLines = 1
// rotating bottom button title text
cell.playerBottomButton.titleLabel?.transform = CGAffineTransform(rotationAngle: (CGFloat.pi / 2))
cell.playerBottomButton.titleLabel!.adjustsFontSizeToFitWidth = true
cell.playerBottomButton.titleLabel!.numberOfLines = 1
return cell
I was expecting the text to be fine after just rotating the UIButton title label 90 degrees to the right.

Different UIFont sizes for different iOS devices in Swift

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
}
}
}

How to set font size of SKLabelNode to fit in fixed size (Swift)

I have a square (200X200) with a SKLabelNode in it. The label shows score and it my be reach a large number. I want fit the number in the square.
How can i change text size (or Size) of a SKLabelNode to fit it in a fixed size.
The size of the frame of the SKLabelNode can be compared against the given rectangle. If you scale the font in proportion to the sizes of the label's rectangle and the desired rectangle, you can determine the best font size to fill the space as much as possible. The last line conveniently moves the label to the center of the rectangle. (It may look off-center if the text is only short characters like lowercase letters or punctuation.)
Swift
func adjustLabelFontSizeToFitRect(labelNode:SKLabelNode, rect:CGRect) {
// Determine the font scaling factor that should let the label text fit in the given rectangle.
let scalingFactor = min(rect.width / labelNode.frame.width, rect.height / labelNode.frame.height)
// Change the fontSize.
labelNode.fontSize *= scalingFactor
// Optionally move the SKLabelNode to the center of the rectangle.
labelNode.position = CGPoint(x: rect.midX, y: rect.midY - labelNode.frame.height / 2.0)
}
Objective-C
-(void)adjustLabelFontSizeToFitRect:(SKLabelNode*)labelNode rect:(CGRect)rect {
// Determine the font scaling factor that should let the label text fit in the given rectangle.
double scalingFactor = MIN(rect.size.width / labelNode.frame.size.width, rect.size.height / labelNode.frame.size.height);
// Change the fontSize.
labelNode.fontSize *= scalingFactor;
// Optionally move the SKLabelNode to the center of the rectangle.
labelNode.position = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect) - labelNode.frame.size.height / 2.0);
}
I have written this for the width, but you can adapt it to the height to fit your CGRect. In the example, pg is a SKLabelNode initialized with the font you are using. Arguments are your String and the target width, and the result is the size you want to assign to your SKLabelNode. Of course, you can also put directly your SKLabelNode. If the size is too big, then the max size is 50, but that's personal.
func getTextSizeFromWidth(s:String, w:CGFloat)->CGFloat {
var result:CGFloat = 0;
var fits:Bool = false
pg!.text=s
if(s != ""){
while (!fits) {
result++;
pg!.fontSize=result
fits = pg!.frame.size.width > w;
}
result -= 1.0
}else{
result=0;
}
return min(result, CGFloat(50))
}
Edit: Actually, I just realized I had also written this:
extension SKLabelNode {
func fitToWidth(maxWidth:CGFloat){
while frame.size.width >= maxWidth {
fontSize-=1.0
}
}
func fitToHeight(maxHeight:CGFloat){
while frame.size.height >= maxHeight {
fontSize-=1.0
}
This expansion of mike663's answer worked for me, and gets there much quicker than going 1 pixel at a time.
// Find the right size by trial & error...
var testingSize: CGFloat = 0 // start from here
var currentStep: CGFloat = 16 // go up by this much. It will be reduced each time we overshoot.
var foundMatch = false
while !foundMatch {
var overShot = false
while !overShot {
testingSize += currentStep
labelNode.fontSize = testingSize
// How much bigger the text should be to perfectly fit in the given rectangle.
let scalingFactor = min(rect.width / labelNode.frame.width, rect.height / labelNode.frame.height)
if scalingFactor < 1 { overShot = true } // Never go over the space
else if scalingFactor < 1.01 { foundMatch = true } // Stop when over 99% of the space is filled
}
testingSize -= currentStep // go back to the last one that didn't overshoot
currentStep /= 4
}
labelNode.fontSize = testingSize // go back to the one we were happy with