Adjust navigation bar title font size to fit text - ios

Is it possible to adjust the font size of the navigation bar's title to fit the text?

You can create a UILabel and set it to UINavigationItem's titleView. See Apple doc: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationItem_Class/#//apple_ref/occ/instp/UINavigationItem/titleView
For the created UILabel, you can set the adjustsFontSizeToFitWidth & minimumScaleFactor properties to let it fit the title. Doc:
https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UILabel_Class/#//apple_ref/occ/instp/UILabel/adjustsFontSizeToFitWidth
Some codes:
- (void)setMyTitle:(NSString *)title
{
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.navigationController.view.bounds.size.width - 100, 44)];
titleLabel.text = title;
titleLabel.font = [UIFont systemFontOfSize:16];
titleLabel.textColor = ...
...
self.navigationItem.titleView = titleLabel;
}

Try the following in viewDidLoad:
NSDictionary *attributes = #{ NSFontAttributeName: [UIFont fontWithName:#"HelveticaNeue-Bold" size:14] };
[self.navigationController.navigationBar setTitleTextAttributes:attributes];
NOTE: The downside to this solution is that you have to know the font size up front and set it manually. I'm not sure if you can set the navigation bar's title label to automatically change the font size to fit the text.
EDIT:
Turns out you can set the navigation bar's label to resize the font size dynamically

Swift 5
private var isFirst = true
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
guard isFirst else {
return
}
isFirst = false
// Adjust Navigation Title by text
if let navigationController = navigationController {
let bar = navigationController.navigationBar
var minX: CGFloat = 0
var maxX: CGFloat = bar.bounds.width
if let lastLeft = navigationItem.leftBarButtonItems?.last, let leftView = lastLeft.view, let buttonBarStackViewFrame = leftView.superview?.frame {
minX = buttonBarStackViewFrame.maxX
}
if let firstRight = navigationItem.rightBarButtonItems?.first, let rightView = firstRight.view, let buttonBarStackViewFrame = rightView.superview?.frame {
maxX = buttonBarStackViewFrame.minX
}
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: maxX - minX, height: bar.bounds.height))
titleLabel.text = LocStr(.favorite_master_title)
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.3
titleLabel.textColor = UIColor.white
titleLabel.textAlignment = .center
if UIDevice.current.modelName.contains(PLUS) {
titleLabel.font = UIFont(name: GENERAL_FONT_NAME, size: PLUS_NAVIGATION_BAR_TITLE_FONT)!
} else {
titleLabel.font = UIFont(name: GENERAL_FONT_NAME, size: GENERAL_NAVIGATION_BAR_TITLE_FONT)!
}
navigationItem.titleView = titleLabel
}
}
with a Extension
extension UIBarButtonItem {
var view: UIView? {
return value(forKey: "view") as? UIView
}
}

Related

I cannot stretch the height of the titleView in the UINavigationBar

This is my code:
class UINavigationControllerCustom : UINavigationController {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews();
navigationBar.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 120);
}
}
class PreferenceInput: UIViewController {
override func viewDidLoad() {
let l1 = UILabel()
l1.backgroundColor = .clear
l1.numberOfLines = 1
l1.font = UIFont.boldSystemFont(ofSize: 30.0)
l1.textAlignment = .left
l1.textColor = .black
l1.text = "Bold title"
l1.sizeToFit();
let l2 = UILabel()
l2.backgroundColor = .clear
l2.numberOfLines = 2
l2.font = UIFont.boldSystemFont(ofSize: 16.0)
l2.textAlignment = .left
l2.textColor = .darkGray;
l2.text = "This is a\nmultiline string for the navBar"
l2.sizeToFit();
let tView = UIStackView(arrangedSubviews: [l1,l2]);
tView.axis = .vertical;
let spacer = UIView()
let constraint = spacer.widthAnchor.constraint(greaterThanOrEqualToConstant: CGFloat.greatestFiniteMagnitude)
constraint.isActive = true
constraint.priority = .defaultLow
let stack = UIStackView(arrangedSubviews: [tView, spacer])
stack.axis = .horizontal
navigationItem.titleView = stack
navigationItem.titleView.sizeToFit();
}
}
And this is what I get:
I can set the height of the navigation bar but how and where should I set the constraint to stretch the height in respect of the given 120px of the custom navigation controller?
I want to provide an individual height of the navigation bar.

Set subviews to correct dimensions after parent view has scaled

I am creating a UIView programtically that is scaled and translated to the center of my view. I am then adding subviews (UILabel's) to that view programatically and the issue I have encountered is that the text for the UILabel's is stretched and difficult to read. I have tried to set autoresizeSubviews = false however this did not have any effect. I have also tried setting the number of lines but this did not have any affect either. I wanted to know if there was a possible solution to this problem that perhaps I am overlooking. Below is my code...
Here i instantiate each UI object to be used on view including view itself
//create lazy vars for UIView that is instantiated until it is initialized
lazy var enlargedView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.white
view.layer.cornerRadius = 12.0
view.clipsToBounds = true
return view
}()
lazy var profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.frame = CGRect(x: self.enlargedView.center.x, y: self.enlargedView.bounds.origin.y + 20.0, width: self.enlargedView.bounds.width * 0.4, height: self.enlargedView.bounds.width * 0.4)
imageView.layer.cornerRadius = imageView.frame.width / 2
imageView.clipsToBounds = true
imageView.layer.borderColor = UIColor.black.cgColor
imageView.layer.borderWidth = 1.0
imageView.contentMode = .scaleAspectFit
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
lazy var usernameLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.textColor = UIColor.black
let font = UIFont(name: Constants.Fonts.GILL_SANS_SEMIBOLD, size: 8.0)
let fontMetrics = UIFontMetrics(forTextStyle: .body)
label.font = fontMetrics.scaledFont(for: font!)
label.textAlignment = .center
//label.sizeToFit()
label.translatesAutoresizingMaskIntoConstraints = false
return label
} ()
lazy var userDataLabel: UILabel = {
let label = UILabel()
//creates implicit height for label
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.textColor = UIColor.black
let font = UIFont(name: Constants.Fonts.GILL_SANS, size: 10.0)
let fontMetrics = UIFontMetrics(forTextStyle: .body)
label.font = fontMetrics.scaledFont(for: font!)
label.textAlignment = .center
label.sizeToFit()
label.translatesAutoresizingMaskIntoConstraints = false
return label
} ()
Next I create animation for view to scale and translate once a collectionView cell is tapped
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchCell", for: indexPath) as! SearchCell
let currentFrame = cell.frame
let selectedUser = userNameArr[indexPath.row]
enlargedView.frame = currentFrame
let backgroundView = UIView(frame: self.view.bounds)
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveEaseOut, animations: {
self.view.addSubview(self.enlargedView)
//translate view to center of screen
self.enlargedView.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.midY)
//while view is being translated background subview should be inserted
self.view.insertSubview(backgroundView, belowSubview: self.enlargedView)
self.enlargedView.transform = CGAffineTransform(scaleX: 2.5, y: 2.5)
}) { (viewWasEnlarged) in
if viewWasEnlarged {
if let profile = selectedUser.user_photo_url {
self.profileImageView.kf.setImage(with: URL(string:Constants.Server.MEDIA_URL + profile))
} else {
self.profileImageView.image = UIImage(named: "user_icon")
}
self.enlargedView.addSubview(self.profileImageView)
self.profileImageView.snp.makeConstraints { (make) in
make.centerX.equalToSuperview()
make.top.equalTo(self.enlargedView.snp.top).offset(20.0)
make.width.equalTo(self.enlargedView.snp.width).multipliedBy(0.4)
make.height.equalTo(self.enlargedView.snp.width).multipliedBy(0.4)
}
//USERNAME label
self.usernameLabel.text = selectedUser.user_name!
self.enlargedView.addSubview(self.usernameLabel)
self.usernameLabel.snp.makeConstraints { (make) in
make.centerX.equalToSuperview()
make.width.equalTo(self.enlargedView.snp.width).multipliedBy(0.9)
make.top.equalTo(self.profileImageView.snp.bottom).offset(5.0)
}
//reset enlarged view back to original value
self.usernameLabel.transform = CGAffineTransform.identity
//USER DATA label
var userAge = ""
var userRelationshipStatus = ""
if let userYear = selectedUser.user_birthday {
let yr = self.calendar.dateComponents([.year], from: userYear).year
userAge = "\(yr!)"
}
if let status = selectedUser.user_stats {
userRelationshipStatus = status
}
self.userDataLabel.text = userAge + " | " + userRelationshipStatus
self.enlargedView.addSubview(self.userDataLabel)
self.userDataLabel.snp.makeConstraints { (make) in
make.centerX.equalToSuperview()
make.width.equalTo(self.enlargedView.snp.width).multipliedBy(0.2)
make.top.equalTo(self.usernameLabel.snp.bottom).offset(3.0)
}
//create label to show HUB as well
//create bio
//show Path??
}
}
The imageView is unaffected however the text itself is not reflected correctly

UITextField not responding

Hi i have created a view programmatically. With in that i have added label and text field. But When i tap on text field, text field is not working. It is not even call its delegate methods. Please help on this.
in for Loop i am calling this return method for creating Text field
widgetsView.addSubview(createTextFieldForDropDown(entity,ival:i,ypos: posY))
//Method to create view with text field and lable
func createTextFieldForDropDown(entity:ListingCategoryFeaturesEntity,ival:Int,ypos:CGFloat) -> UIView
{
var posY = ypos
var posX = CGFloat(0)
let width = (SCREEN_WIDTH/2)-15
var height = CGFloat(40)
let viewRadio = UIView()
viewRadio.frame = CGRectMake(posX, posY, width, height)
viewRadio.backgroundColor = UIColor.greenColor()
height = 40
posY = 0
let lblTitle = UILabel()
lblTitle.frame = CGRectMake(posX, posY, width, height)
lblTitle.text = entity.strDisplayName
lblTitle.backgroundColor = UIColor.redColor()
lblTitle.font = GRAPHICS.FONT_REGULAR(16)
viewRadio.addSubview(lblTitle)
let tag = 9000
posX = lblTitle.frame.maxX+10
var textField = UITextField()
textField.frame = CGRectMake(posX, posY, width, height)
textField = returnTextFieldsProperties(textField, placeHolderText: "", tagValue: tag+ival)
textField.backgroundColor = UIColor.blueColor()
textField.becomeFirstResponder()
viewRadio.addSubview(textField)
return viewRadio
}
//Method to retrun text field properties
func returnTextFieldsProperties(textField : UITextField ,placeHolderText : String ,tagValue : Int) -> UITextField
{
textField.attributedPlaceholder = NSAttributedString(string:placeHolderText,
attributes:[NSForegroundColorAttributeName: UIColorFromRGB(colorLightGray, alpha: 1.0)])
textField.font = GRAPHICS.FONT_REGULAR(14)
textField.textAlignment = NSTextAlignment.Left
textField.textColor = UIColor.blackColor()
textField.delegate = self
textField.userInteractionEnabled = true
textField.returnKeyType = UIReturnKeyType.Next
let view_left = UIView()
view_left.frame = CGRectMake(20,0,10,textField.frameHeight)
textField.leftView = view_left
textField.leftViewMode = UITextFieldViewMode.Always
textField.borderStyle = UITextBorderStyle.RoundedRect
textField.backgroundColor = UIColor.clearColor()
textField.autocorrectionType = .No
textField.tag = tagValue
return textField
}
Try to remove:
textField.becomeFirstResponder()
This may be the problem since you have all your text fields marked with that, but what you want, I assume, is that only the text field that you tapped should be a first responder.
The problem is that your textField is not within the bounds of its superview viewRadio. Make the viewRadio wide enough to hold both the label and the textView:
Change:
viewRadio.frame = CGRectMake(posX, posY, width, height)
to:
viewRadio.frame = CGRectMake(posX, posY, SCREEN_WIDTH, height)
I think you did not set the delegate method, check the below used in your project,
import UIKit
class ViewController: UIViewController, UITextFieldDelegate
if you create the textfield initially set the delegate method is,
var textField = UITextField()
textField.frame = CGRectMake(posX, posY, width, height)
textField = returnTextFieldsProperties(textField, placeHolderText: "", tagValue: tag+ival)
**textField.delegate = self**
textField.backgroundColor = UIColor.blueColor()
viewRadio.addSubview(textField)
hope its helpful
Simple answer, just write delegate method and set delegate of UITextField in storyboard or manually in viewDidLoad
Write something like this, And It will work Perfectly.
extension LoginVC : UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}

Swift: ViewController Title Size in Code?

I have a ViewController.
I added a Title to the Viewcontroller.
Its a variable.
var Title: String! = "🎯"
override func viewDidLoad() {
super.viewDidLoad()
self.title = Title
}
Is there a way, to make the font bigger?
This way you can customise your navigation title:
self.title = "🎯"
var attributes = [NSFontAttributeName: UIFont(name: "Avenir", size: 20)!] //change size as per your need here.
self.navigationController?.navigationBar.titleTextAttributes = attributes
Make a Title View Label and assign it to the navigation item.
code for it is:
var tlabel = UILabel(frame: CGRectMake(0, 0, 300, 40))
tlabel.text = self.navigationItem.title;
tlabel.textColor = UIColor.whiteColor()
tlabel.backgroundColor = UIColor.whiteColor()
tlabel.adjustsFontSizeToFitWidth = true
self.navigationItem.titleView = tlabel
Here is the possible work around. You can assign any UIView to a navcontroller's title area.
Create a UILabel and set its font and size anyway you want, then assign it to the UIViewController's navigationItem.titleView property. Make sure the UILabel's backgroundColor is set to clearColor.
UILabel *labelTitle = UILabel(frame: CGRectZero);
labelTitle.text = "Title";
labelTitle.font = UIFont(name: "Your-Font-Name", size: SIZE)
labelTitle.text.textAlignment = NSTextAlignment.Center
self.navigationItem.titleView = labelTitle;

UILabel resizes its SuperView?

I have the following view which contains a UILabel:
class MyView : UIView {
func viewDidLoad() {
self.autoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth
bottomView = UIView(frame: CGRectMake(self.bounds.origin.x, self.bounds.origin.y + self.imageView!.bounds.size.width, self.bounds.size.width, self.bounds.size.height - self.imageView!.bounds.size.height))
// bottomView frame calculation is: (0.0, 355.0, 355.0, 130.0)
bottomView?.backgroundColor = UIColor.greenColor()
bottomView?.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomView?.clipsToBounds = true
self.addSubview(self.bottomView!)
var descriptionRect: CGRect = CGRectInset(self.bottomView!.bounds, leftRightInset, 20/2)
let descriptionLabel = UILabel()
descriptionLabel.numberOfLines = 3
descriptionLabel.autoresizingMask = UIViewAutoresizing.FlexibleWidth
descriptionLabel.font = UIFont(name: MGFont.helvetica, size: 22)
descriptionLabel.textColor = UIColor.whiteColor()
descriptionLabel.textAlignment = NSTextAlignment.Left
descriptionLabel.backgroundColor = UIColor.blueColor()
var paragraphStyle:NSMutableParagraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 1.0
paragraphStyle.lineBreakMode = NSLineBreakMode.ByTruncatingTail
let attributes = [NSParagraphStyleAttributeName : paragraphStyle]
descriptionLabel.attributedText = NSAttributedString(string: previewCard.title, attributes:attributes)
bottomView?.addSubview(descriptionLabel)
descriptionLabel.bounds = descriptionRect
descriptionLabel.sizeToFit()
descriptionLabel.center = CGPointMake(bottomView!.bounds.width/2, bottomView!.bounds.height/2 - hotelNameLableHeight/2)
}
}
The height of the bottomView should always be fixed.
MyView is resized during runtime. This means that the green bottom view also increases in size.
Here is the result when the label has two and three lines:
It appears that the UILabel resizes its super view.
Note that I do not use AutoLayout.
override func layoutSubviews() {
super.layoutSubviews()
}
How can I prevent the UILabel from resizing its SuperView?
Edit: I also tried to comment bottomView?.clipsToBounds = true
Override setFrame: and setBounds: of the super view (subclass if they're plain UIViews), add breakpoints, and see the stack trace to find out what's causing them to resize.
There is no need to set the autoResizingMask on the label, just set the frame and it will get automatically centered. And of course you can set the insets for the UILabel accordingly. I've add below testing code FYI:
override func viewDidLayoutSubviews() {
addTestView(CGRectMake(0, 200, view.bounds.width, 50), labelStr: "I am a short testing label")
addTestView(CGRectMake(0, 260, view.bounds.width, 50), labelStr: "I am a very longlonglonglonglonglonglong testing label")
addTestView(CGRectMake(0, 320, view.bounds.width, 50), labelStr: "I am a very longlonglonglonglonglonglonglonglonglonglonglong testing label. Will be truncated")
}
func addTestView(frame:CGRect, labelStr: String){
let bottomView = UIView(frame:frame)
bottomView.backgroundColor = UIColor.greenColor()
bottomView.autoresizingMask = UIViewAutoresizing.FlexibleWidth
bottomView.clipsToBounds = true
view.addSubview(bottomView)
var label = UILabel(frame: bottomView.bounds)
label.textAlignment = NSTextAlignment.Left
label.numberOfLines = 0
label.text = labelStr
bottomView.addSubview(label)
}

Resources