Make custom title view click able swift - ios

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

Related

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

Swift - response view in every view?

I've got a small question: is it possible somehow (without storyboard) to create a little view at the top of the screen (if there's a navigationbar, then under that), that displays errors / responses if needed?
Without creating views on every single viewController I made, just by code?
Or is there some extension you could recommend?
For example: "No Internet Connection"
You can check this answer - https://stackoverflow.com/a/49129636/6080920
Code required
extension UIViewController
{
func showNotificationView(message : String)
{
//base View
let baseView = UIView(frame: CGRect(x: 20, y: self.view.frame.size.height-(self.view.frame.size.height*0.15), width: self.view.frame.size.width-40, height: self.view.frame.size.height*0.08))
baseView.backgroundColor = UIColor.gray
baseView.clipsToBounds=true
self.view.addSubview(baseView)
//Image View
let imageView = UIImageView(image: UIImage(named: "RM_3"))
imageView.clipsToBounds=true
imageView.frame = CGRect(x: 0, y: 0, width: baseView.frame.size.width*0.2, height: baseView.frame.size.height)
baseView.addSubview(imageView)
//Label
let textLabel = UILabel(frame: CGRect(x: baseView.frame.size.width*0.2+10, y: 0, width: baseView.frame.size.width, height: baseView.frame.size.height))
textLabel.textColor = UIColor.white
textLabel.backgroundColor = UIColor.clear
textLabel.textAlignment = .left;
textLabel.numberOfLines = 0
textLabel.font = UIFont(name: "Montserrat-Light", size: 12.0)
textLabel.text = message
baseView.addSubview(textLabel)
}
}
Usage
#IBAction func navigate(_ sender: Any) {
self.showNotificationView(message: "hihihihh")
}

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 set width of navigationTitleView and Truncate label by swift3

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:

Swift how to make for navigation middle section image and text next to each other

I have searched a lot on stackoverflow and I havent been able to find solution for my problem which is that I need to put in navigationBar in middle section image and text next to each other but apparently I was able only to place just image or just text
Here is my code
let nav = self.navigationController?.navigationBar
nav?.barStyle = UIBarStyle.Default
nav?.tintColor = UIColor.blackColor()
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "icon_heart")
imageView.image = image
self.navigationItem.title = "App name"
self.navigationItem.titleView = imageView
I am aware that it on this way it accept only image which is titleView but I cant think of some normal solution and dont know is it even possible. Also if that is not possible how can I make then blank image and draw that icon image and text next to each other and append then that new image.
Edit:
Based on awph answer I have added code like this and it works fine for my case where I have always same characters in title
let screenSize: CGRect = UIScreen.mainScreen().bounds
let nav = self.navigationController?.navigationBar
nav?.barStyle = UIBarStyle.Default
nav?.tintColor = UIColor.blackColor()
let imageView = UIImageView(frame: CGRect(x: screenSize.width / 2 - 40, y: 15, width: 20, height: 20))
imageView.contentMode = .ScaleAspectFit
let image = UIImage(named: "icon_heart")
imageView.image = image
nav!.addSubview(imageView)
// label on top of the application that contain word
var label = UILabel(frame: CGRectMake(0, 0, 0, 0))
label.center = CGPointMake(screenSize.width / 2 - 15, 17)
label.textColor = UIColor.blackColor()
label.font = UIFont.systemFontOfSize(14)
label.textAlignment = NSTextAlignment.Center
label.text = "App Name"
label.sizeToFit()
nav!.addSubview(label)
You right, as said in documentation:
// Custom view to use in lieu of a title. May be sized horizontally. Only used when item is topmost on the stack.
What you need to do is to create an UIView, add an UImageView (that contains your image) as subview (view.addSubview(imageView)) and then add a UILabel on it view.addSubview(label).

Resources