how to set width of navigationTitleView and Truncate label by swift3 - ios

I have a problem about navigation titleView.
The titleView cover my right barbuttonItem and out of screen.
I need titleView just in center region and have right region for barbuttonItem.
I want to know how to set width about my title, because I can't set width successfully.
And I also want to truncating middle the label.
What's wrong with me?
Thanks.
Here is Image about my question.
Here is Image about my question.
self.navigationItem.titleView = setTitle(title: name, subtitle: "")
func setTitle(title:String, subtitle:String) -> UIView {
let titleLabel = UILabel(frame: CGRect(x:0, y:5, width:0, height:0))
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.white
titleLabel.font = defaultTitleFont
titleLabel.text = title
titleLabel.sizeToFit()
let subtitleLabel = UILabel(frame: CGRect(x:5, y:18, width:0, height:0))
subtitleLabel.backgroundColor = UIColor.clear
subtitleLabel.textColor = UIColor.red
subtitleLabel.font = UIFont.systemFont(ofSize: 20)
subtitleLabel.text = subtitle
subtitleLabel.sizeToFit()
let titleView = UIView(frame: CGRect(x:0, y:0, width:max(titleLabel.frame.size.width, subtitleLabel.frame.size.width), height:35))
titleView.addSubview(titleLabel)
//titleView.addSubview(subtitleLabel)
let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width
if widthDiff > 0 {
var frame = titleLabel.frame
frame.origin.x = widthDiff / 2
titleLabel.frame = frame.integral
} else {
var frame = subtitleLabel.frame
frame.origin.x = abs(widthDiff) / 2
subtitleLabel.frame = frame.integral
}
return titleView
}

You have to calculate the title view size/frame beforehand.
One possible way to do this to take consideration of screen width and number of bar button items presented in the navigation bar.
Take a look at the following code (Simplified for showing only title, no subtitle):
func getTitleView (title:String, numOfButtons: Int = 0) -> UIView {
let barButtonSize = 70
let offset: CGFloat = CGFloat(numOfButtons * barButtonSize)
let frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width - offset, height: 35)
let titleView = UIView(frame:frame)
let titleLabel = UILabel(frame: titleView.bounds)
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.red
titleLabel.font = UIFont.systemFont(ofSize: 14)
titleLabel.text = title
titleLabel.numberOfLines = 1
titleLabel.textAlignment = .center
titleLabel.lineBreakMode = .byTruncatingMiddle
titleView.addSubview(titleLabel)
return titleView
}
And from viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .camera, target: self, action: nil)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .bookmarks, target: self, action: nil)
self.navigationItem.titleView = getTitleView(title: "Wow Wow Wow Wow Wow Wow Wow Wow Wow Wow Wow Wow Wow Wow Wow WowWow Wow Wow Wow Wow Wow Wow WowWow WowWowWowWowWowWowWowWow Wow Wow Wow Wow Wow Wow Wow!!", numOfButtons: 2)
}
And output:

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.

Make custom title view click able swift

I customise the title view add a image and labels in it know I want to make it clickable but its not working. I added tap gesture in title view but its not working.
here is my code.
func navTitleWithImageAndText(titleText: String,subTitleText:String, imageName: String) -> UIView {
// Creates a new UIView
let titleView = UIView()
let label = UILabel(frame: CGRect(x: 0, y: -15, width: 0, height: 0))
// Creates a new text label
// let label = UILabel()
label.text = titleText
label.font = UIFont.boldSystemFont(ofSize: 17)
//label.center = titleView.center
label.textColor = .white
//label.textAlignment = NSTextAlignment.center
label.sizeToFit()
let subtitleLabel = UILabel(frame: CGRect(x: 0, y: 5, width: 0, height: 0))
subtitleLabel.backgroundColor = UIColor.clear
subtitleLabel.textColor = UIColor.white
subtitleLabel.font = UIFont.systemFont(ofSize: 12)
subtitleLabel.text = subTitleText
subtitleLabel.sizeToFit()
// Creates the image view
let image = UIImageView()
image.image = UIImage(named: imageName)
// Maintains the image's aspect ratio:
let imageAspect = image.image!.size.width / image.image!.size.height
// Sets the image frame so that it's immediately before the text:
let imageX = label.frame.origin.x - label.frame.size.height * imageAspect - 20
let imageY = label.frame.origin.y
let imageWidth = label.frame.size.height * imageAspect + 15
let imageHeight = label.frame.size.height + 15
image.frame = CGRect(x: imageX, y: imageY, width: imageWidth, height: imageHeight)
image.contentMode = UIView.ContentMode.scaleAspectFit
// Adds both the label and image view to the titleView
titleView.addSubview(label)
titleView.addSubview(image)
titleView.addSubview(subtitleLabel)
// Sets the titleView frame to fit within the UINavigation Title
titleView.sizeToFit()
return titleView
}
add tap gesture in it. but why its not working.
titleView.addGestureRecognizer(titleGestureRecognizer)
I have implemented a tap gesture on a label in the following way:-
Initialize Variable
var tap_gest = UITapGestureRecognizer()
Add gesture on Label. Add the following code in "viewDidLoad()"
if normal label then use below
self.register_as_company_lbl.isUserInteractionEnabled = true // register_as_company_lbl is my label where tap gesture added
self.tap_gest.addTarget(self, action: #selector(registerAsComapany))
self.register_as_company_lbl.addGestureRecognizer(tap_gest)
if on navigation bar title then use below
self.navigationController?.navigationBar.addGestureRecognizer(tap_gest)
Define Selector method in your ViewController Class as following
#objc func registerAsComapany(){//Add your task what you perform, In my case I have to push to another screen
let vc = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CompanyDetailsViewController") as! CompanyDetailsViewController
self.navigationController?.pushViewController(vc , animated: true)
}
titleView.isUserInteractionEnabled = true

issue with title in navigation bar in arabic

I am having an issue with this function:
func setTitle(title:String, subtitle:String) -> UIView {
let titleLabel = UILabel(frame: CGRect(x:0, y:-5, width:0, height:0))
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.gray
titleLabel.font = UIFont.boldSystemFont(ofSize: 17)
titleLabel.text = title
titleLabel.sizeToFit()
let subtitleLabel = UILabel(frame: CGRect(x:0, y:18, width:0, height:0))
subtitleLabel.backgroundColor = UIColor.clear
subtitleLabel.textColor = UIColor.black
subtitleLabel.font = UIFont.systemFont(ofSize: 12)
subtitleLabel.text = subtitle
subtitleLabel.sizeToFit()
let titleView = UIView(frame: CGRect(x:0, y:0, width:max(titleLabel.frame.size.width, subtitleLabel.frame.size.width), height:30))
titleView.addSubview(titleLabel)
titleView.addSubview(subtitleLabel)
let widthDiff = subtitleLabel.frame.size.width - titleLabel.frame.size.width
if widthDiff > 0 {
var frame = titleLabel.frame
frame.origin.x = widthDiff / 2
titleLabel.frame = frame.integral
} else {
var frame = subtitleLabel.frame
frame.origin.x = abs(widthDiff) / 2
titleLabel.frame = frame.integral
}
return titleView
}
// Use :
self.navigationItem.titleView = setTitle("title", "subtitle")
// Source : http://stackoverflow.com/questions/12914004/uinavigationbar-titleview-with-subtitle
as shown above images, whenever someone writes in arabic[picture 2] the title will be messed up, but if someone wrote it in English[picture 1]. the label of title will remain good.
thank you in advance.
I ran code with all combinations of arabic and english words and found the problem in code. Check it out.
if widthDiff > 0 {
var frame = titleLabel.frame
frame.origin.x = widthDiff / 2
titleLabel.frame = frame.integral
} else {
var frame = subtitleLabel.frame
frame.origin.x = abs(widthDiff) / 2
titleLabel.frame = frame.integral /* subtitleLabel.frame = frame.integral */
}

Why setting titleView lowers header text?

I'm trying to dynamically set my navigation bar's text so that the header text always fits. I'm acccomplishing that like this:
// Pet's Day text "Joy's Day"
if let range = currentPet.range(of: "_") {
let petsName = currentPet[range.upperBound..<currentPet.endIndex]
let deviceWidth = UIScreen.main.bounds.size.width
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: deviceWidth, height: 40))
titleLabel.text = "\(petsName)'s Day"
titleLabel.font = UIFont.systemFont(ofSize: 30)
titleLabel.backgroundColor = UIColor.clear
titleLabel.textColor = UIColor.white
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.5
titleLabel.textAlignment = .center
self.navBar.topItem?.titleView = titleLabel
}
However, as seen by this picture, this lowers the header text below its natural height:
The navigation bar on the left is from one of my app's other views, while the one on the right is the one I'm setting.
Both of these navigation bars are navigation bars that I've dragged in and made the prompt equal to an empty string to increase their height:
Can anybody please help me implement my code above so that it doesn't drop down the header text?
**Edit: Here are screenshots from Xcode's debug hierarchy:
This is the normal navigation bar:
This is the one I'm setting:
You need to set the baseline, by default is Align Baseline, you need to change to Align Centers
Code example:
class TestViewController: UIViewController {
#IBOutlet weak var navBar: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
// Change the height of the navbar
self.navBar.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: 68)
let deviceWidth = UIScreen.main.bounds.size.width
let titleLabel = UILabel(frame: CGRect(x: 0, y: 0, width: deviceWidth, height: 40))
titleLabel.text = "Log Events" // Change to Joy's Day and check the result
titleLabel.font = UIFont.systemFont(ofSize: 30)
titleLabel.baselineAdjustment = .alignBaselines
titleLabel.textColor = UIColor.white
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.minimumScaleFactor = 0.5
titleLabel.textAlignment = .center
self.navBar.topItem?.titleView = titleLabel
}
}

How to make iOS navigationItem.titleView align to the left?

navigationItem.hidesBackButton = true
navigationItem.leftBarButtonItem = nil
head = UIView()
head.frame = CGRectMake(0, 0, 200, 44)
head.frame.origin.x = CGFloat(0)
navigationItem.titleView = head
I attempt to align the titleView to the left, but it still remains in the middle.
Try this:
let title = UILabel()
title.text = "TITLE"
let spacer = UIView()
let constraint = spacer.widthAnchor.constraint(greaterThanOrEqualToConstant: CGFloat.greatestFiniteMagnitude)
constraint.isActive = true
constraint.priority = .defaultLow
let stack = UIStackView(arrangedSubviews: [title, spacer])
stack.axis = .horizontal
navigationItem.titleView = stack
The idea is that main view (in this case title) will take all the space it needs and spacer view will take all the free space left.
I figured it out.
I just need to set my custom UIView as the leftBarButtonItem.
I had a similar requirement of adding the Title along with the subtitle to the left of the navbar. I couldn't achieve it with a TitleView since it cannot be aligned left.
So I took #TIMEZ and #Wain's answers, along with responses from the thread here and added a complete answer, in case it helps anyone :
let titleLabel = UILabel()
titleLabel.text = "Pillars"
titleLabel.textAlignment = .center
titleLabel.font = .preferredFont(forTextStyle: UIFont.TextStyle.headline)
let subtitleLabel = UILabel()
subtitleLabel.text = "How did you do today?"
subtitleLabel.textAlignment = .center
subtitleLabel.font = .preferredFont(forTextStyle: UIFont.TextStyle.subheadline)
let stackView = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel])
stackView.distribution = .equalSpacing
stackView.alignment = .leading
stackView.axis = .vertical
let customTitles = UIBarButtonItem.init(customView: stackView)
self.navigationItem.leftBarButtonItems = [customTitles]
You can't align a title view to the left. You can create a title view and add a subview positioned to its left. If you're looking to display in place of the back button then you should be using a bar button item instead of title view.
I don't think Apple wants you to do that. Navigation bars have a pretty specific purpose that often involves having something else in the top left corner like a Back button. You might be better off making a custom UIView or UIToolbar that looks like the navigation bar.
If it's a custom UIView, override intrinsicContentSize and return
CGSize(width: .greatestFiniteMagnitude, height: UIView.noIntrinsicMetric)
This will stretch the view to the entire width between left and right bar button items.
You can constraint the titleView to the navigationBars leftAnchor.
private func setupNavigationBarTitleView() {
let titleView = YourCustomTitleView()
navigationBarTitleView = titleView
navigationBarTitleView?.translatesAutoresizingMaskIntoConstraints = false
navigationItem.titleView = navigationBarTitleView
if let navigationBar = navigationController?.navigationBar {
NSLayoutConstraint.activate([
titleView.leadingAnchor.constraint(equalTo: navigationBar.leadingAnchor, constant: 16),
titleView.heightAnchor.constraint(equalToConstant: 36)
])
}
}
The simplest solution is to add low priority constraint for title width.
let titleLabel = UILabel()
titleLabel.textAlignment = .left
...
let c = titleLabe.widthAnchor.constraint(equalToConstant: 10000)
c.priority = .required - 1
c.isActive = true
navigationItem.titleView = titleLabel
Hey guys after trying most of the solutions above. I found that most of em still did not meet my prod requirements. Here is a solution I came up with after trying out different solutions.
func setLeftAlignTitleView(font: UIFont, text: String, textColor: UIColor) {
guard let navFrame = navigationController?.navigationBar.frame else{
return
}
let parentView = UIView(frame: CGRect(x: 0, y: 0, width: navFrame.width*3, height: navFrame.height))
self.navigationItem.titleView = parentView
let label = UILabel(frame: .init(x: parentView.frame.minX, y: parentView.frame.minY, width: parentView.frame.width, height: parentView.frame.height))
label.backgroundColor = .clear
label.numberOfLines = 2
label.font = font
label.textAlignment = .left
label.textColor = textColor
label.text = text
parentView.addSubview(label)
}
let navLabel = UILabel(frame: CGRect(x: 0, y: 0, width: view.frame.width - 32, height: view.frame.height))
navLabel.text = "Hi, \(CurrentUser.firstName)"
navLabel.textColor = UIColor.white
navLabel.font = UIFont.systemFont(ofSize: 20)
navigationItem.titleView = navLabel

Resources