UINavigationBar contentMode not being set - ios

I am trying to make the background of the UINavigationBar an image, and the image isn't the exact size of the bar. I can't seem to set the contentMode of the bar correctly for some reason. This is the code I have:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// ...
let image = UIImage(named: object?.imageName ?? "")
navigationController?.navigationBar.alpha = 0
navigationController?.navigationBar.setBackgroundImage(image, for: .default)
self.navigationController?.navigationBar.contentMode = .scaleAspectFill
UIView.animate(withDuration: Double(UINavigationControllerHideShowBarDuration), animations: {
self.navigationController?.navigationBar.alpha = 1
})
}
I don't know what I'm doing wrong, or maybe contentMode just doesn't do anything for UINavigationBar.
What's currently happening is the background image is just presented again like mosaic
Thanks

You can create UIView and add Image and Text to it, but you must set constraints
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
titleView.addSubview(containerView)
let profileImageView = UIImageView()
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = 20
profileImageView.clipsToBounds = true
containerView.addSubview(profileImageView)
profileImageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
self.navigationItem.titleView = titleView
titleView.addGestureRecognizer(UITapGestureRecognizer(target:
self, action: #selector(func)))
I hope that I helped you

Related

UITapGestureRecognizer not working on UIView in the navigationBar titleView?

I am trying to add tapGesture on navigationBar titleView but not getting any event. Please tell me how to resolve this issue.
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 60)
titleView.backgroundColor = UIColor.yellow
let profileImageView = UIImageView()
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = 20
profileImageView.clipsToBounds = true
profileImageView.loadImageUsingCacheWithUrlString(urlString: user.image)
titleView.addSubview(profileImageView)
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.leftAnchor.constraint(equalTo: titleView.leftAnchor).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
let nameLabel = UILabel()
nameLabel.text = user.name
nameLabel.font = UIFont(name: "HelveticaNeue-Medium", size: 17)
titleView.addSubview(nameLabel)
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true
nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true
nameLabel.rightAnchor.constraint(equalTo: titleView.rightAnchor).isActive = true
nameLabel.heightAnchor.constraint(equalTo: profileImageView.heightAnchor).isActive = true
self.navigationItem.titleView = titleView
titleView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showChatTableViewController)))
Make sure to set isUserInteractionEnabled to true. By default it true but if it's not working in your case then try to set true
Make sure to debug your code and check that after adding titleView are you able to print out self.navigationItem.titleView ?
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 60)
titleView.backgroundColor = UIColor.yellow
titleView.isUserInteractionEnabled = true
self.navigationItem.titleView = titleView
titleView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(showChatTableViewController)))
#objc func showChatTableViewController() {
print("tapped")
}

swift can't call function after clicking button

I have made a container view with a image view and a button inside for some reason when running the app in simulator i can't click button and call the function taking me to the next screen , i have encountered this kind of problem before and it was as simple as changing the button to a lazy var though that hasn't work on this occasion?
lazy var nameLabelButton = UIButton()
func setupNavBarWithUser() {
guard let displayName = user?.DisplayName else { return }
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
titleView.backgroundColor = UIColor.red
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
titleView.addSubview(containerView)
let profileImageView = UIImageView()
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.contentMode = .scaleAspectFill
profileImageView.layer.cornerRadius = 20
profileImageView.clipsToBounds = true
if let profileImageUrl = user?.profileImageURL {
profileImageView.loadImageUsingCacheWithUrlString(urlString:profileImageUrl)
}
containerView.addSubview(profileImageView)
//ios 9 constraint anchors
//need x,y,width,height anchors
profileImageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
containerView.addSubview(nameLabelButton)
nameLabelButton.setTitle("\(displayName)", for: .normal)
nameLabelButton.setTitleColor(.black, for: .normal)
nameLabelButton.translatesAutoresizingMaskIntoConstraints = false
//need x,y,width,height anchors
nameLabelButton.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true
nameLabelButton.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true
nameLabelButton.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
nameLabelButton.heightAnchor.constraint(equalTo: profileImageView.heightAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: titleView.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true
nameLabelButton.addTarget(self, action: #selector(self.openUsersProfileController), for: .touchUpInside)
self.navigationItem.titleView = titleView
}
func openUsersProfileController(){
print("asdasdadsad")
let openUsersProfileController = UserProfileController(collectionViewLayout: UICollectionViewFlowLayout())
openUsersProfileController.user = self.user
navigationController?.pushViewController(openUsersProfileController, animated: true)
}
well, code looks fine you just need to add #objc
#objc func openUsersProfileController(){
print("asdasdadsad")
let openUsersProfileController = UserProfileController(collectionViewLayout: UICollectionViewFlowLayout())
openUsersProfileController.user = self.user
navigationController?.pushViewController(openUsersProfileController, animated: true)
}
Reason:
From Swift 4, we manually need to add #objc before function.

Swift UITapGesture on view in a titleView not working

I have a UINavigationItem and I set it's titleView to a UIView which has a UILabel and UIImageView embedded. I'm attempting to add a UITapGestureRecognizer to the view but it doesn't seem to work. Any solutions? Also, adding a gestureRecognizer to the whole navigationBar isn't an option as I have a rightBarButtonItem and want to make use of the back button.
Here is my code:
func configureTitleView() {
guard let profile = profile else {
// Pop navController
return
}
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
titleView.addSubview(containerView)
let profileImageView = UIImageView()
profileImageView.translatesAutoresizingMaskIntoConstraints = false
profileImageView.contentMode = .scaleAspectFill
profileImageView.clipsToBounds = true
let imageURL = URL(string: profile!.firstProfilePicture!)
profileImageView.sd_setImage(with: imageURL)
containerView.addSubview(profileImageView)
profileImageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
profileImageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 36).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 36).isActive = true
profileImageView.layer.cornerRadius = 36 / 2
let nameLabel = UILabel()
containerView.addSubview(nameLabel)
nameLabel.text = profile!.displayName!
nameLabel.textColor = .white
nameLabel.translatesAutoresizingMaskIntoConstraints = false
nameLabel.leftAnchor.constraint(equalTo: profileImageView.rightAnchor, constant: 8).isActive = true
nameLabel.centerYAnchor.constraint(equalTo: profileImageView.centerYAnchor).isActive = true
nameLabel.rightAnchor.constraint(equalTo: containerView.rightAnchor).isActive = true
nameLabel.heightAnchor.constraint(equalTo: profileImageView.heightAnchor).isActive = true
containerView.centerXAnchor.constraint(equalTo: titleView.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true
self.navigationItem.titleView = titleView
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.openProfile))
tapGesture.numberOfTapsRequired = 1
titleView.addGestureRecognizer(tapGesture)
titleView.isUserInteractionEnabled = true
}
Beginning with iOS 11, views added to toolbars as UIBarButtonItem using UIBarButtonItem(customView:) are now laid out using auto layout. This includes title views added to a UINavigationBar through the navigationItem.titleView property of a UIViewController. You should add sizing constraints on your titleView. For example:
titleView.widthAnchor.constraint(equalToConstant: 100).isActive = true
titleView.heightAnchor.constraint(equalToConstant: 40.0).isActive = true
Otherwise, auto layout will use the intrinsic content size of your title view which is CGSize.zero. Gestures are masked to the bounds of the view they are attached to even if the sub views of that view are not. Because the bounds of titleView without constraints is CGRect.zero it will never fire. Add constraints and it works as expected.
For more information see the WWDC 2017 session Updating your app for iOS 11.
You do not need to add explicit height and width constant constraint to custom view.
Just add subviews to custom view, add width and height anchor.
let customView = UIView()
let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
customView.addSubview(button)
[
button.widthAnchor.constraint(equalTo: customView.widthAnchor),
button.heightAnchor.constraint(equalTo: customView.heightAnchor),
].forEach({$0.isActive = true})
navigationItem.titleView = customView

Swift3 iOS -Rounded ImageView in Navigation TitleView Keeps Showing Square?

I have a rounded imageView that I use for the profile pic in my app. I use the code several times throughout the app in tableView cells and on different views in view controllers. The profile pic always displays as round. When I use the below code to set the profile pic to round inside the navItem's titleView it only displays as a square.
Why doesn't it display round in the navItem's titleView?
var url: String?//it's already set with some value
override func viewDidLoad() {
super.viewDidLoad(){
setTitleView(urlStr: url)
{
func setTitleView(urlStr: String?){
let titleView = UIView()
titleView.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
titleView.addSubview(containerView)
let imageView = UIImageView()
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = imageView.frame.size.width / 2
imageView.clipsToBounds = true
imageView.layer.borderColor = UIColor.white.cgColor
imageView.layer.borderWidth = 0.5
imageView.backgroundColor = UIColor.white
if let urlStr = urlStr{
let url = URL(string: urlStr)
imageView.sd_setImage(with: url!)
}
containerView.addSubview(imageView)
imageView.leftAnchor.constraint(equalTo: containerView.leftAnchor).isActive = true
imageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 40).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 40).isActive = true
containerView.centerXAnchor.constraint(equalTo: titleView.centerXAnchor).isActive = true
containerView.centerYAnchor.constraint(equalTo: titleView.centerYAnchor).isActive = true
navigationItem.titleView = titleView
}
Looks like imageView.layer.cornerRadius = imageView.frame.size.width / 2 is set to 0. imageView.frame.size.width is equal to 0 here.
Instead of let imageView = UIImageView(), you can predefine the frame when creating the imageView with let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))

Why doesn't a tap gesture recognizer work when creating a variable?

I am new to Swift, and I have been working on a project and ran into a peculiar issue that I fixed, but wasn't quite sure why the solution worked.
I have a class UserViewController where I do something like:
class UserViewController: UIViewController {
let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "profilepic")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
imageView.frame = CGRect.init(x: 0, y: 0, width: 30, height: 30) //CGRectMake(0, 0, 30, 30)
imageView.layer.cornerRadius = 0.5 * imageView.bounds.size.width
imageView.clipsToBounds = true
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
func setupView() {
view.addSubview(profileImageView)
profileImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
profileImageView.topAnchor.constraint(equalTo:topLayoutGuide.bottomAnchor, constant: 24).isActive = true
profileImageView.widthAnchor.constraint(equalToConstant: 80).isActive = true
profileImageView.heightAnchor.constraint(equalToConstant: 80).isActive = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleSelectProfilePicture))
profileImageView.addGestureRecognizer(tapGestureRecognizer)
profileImageView.isUserInteractionEnabled = true
}
I was trying to add a tap gesture recognizer to my UIImageView. What I was doing before was actually adding the recognizer in my initialization for profileImageView like this:
let profileImageView: UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "profilepic")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
imageView.frame = CGRect.init(x: 0, y: 0, width: 30, height: 30) //CGRectMake(0, 0, 30, 30)
imageView.layer.cornerRadius = 0.5 * imageView.bounds.size.width
imageView.clipsToBounds = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleSelectProfilePicture))
profileImageView.addGestureRecognizer(tapGestureRecognizer)
profileImageView.isUserInteractionEnabled = true
return imageView
}()
When I was doing this, the recognizer was not working (I would tap on the image and nothing would happen, the handler function was never invoked). When I pulled out the three lines that created/added the gesture recognizer to my image view, and moved them into setupView() the tap was recognized, and everything worked as expected.
For the betterment of my understanding, why is this the case? Why can't I add the gesture recognize in the initialization of my image view and have it work?
Thanks in advance.
You were modifying the not-yet returned variable in these two lines in your old code:
profileImageView.addGestureRecognizer(tapGestureRecognizer)
profileImageView.isUserInteractionEnabled = true
Replace profileImageView with imageView and it will work.

Resources