UIBarButtonItem position incorrect on < iOS 11 - ios

On iOS 10 and below my bar buttons are positioned incorrectly within the nav bar. What could be causing this?
This is the function to set the button:
func setBarButton(image: UIImage?, position: BarButtonPosition, target: AnyObject, selector: Selector) -> Void {
let barButton = UIBarButtonItem(title: "", style: .plain, target: target, action: selector)
barButton.image = image
if position == .left {
navigationItem.leftBarButtonItem = barButton
navigationItem.leftBarButtonItem?.tintColor = UIColor.zbPrimary
} else {
navigationItem.rightBarButtonItem = barButton
navigationItem.rightBarButtonItem?.tintColor = UIColor.zbPrimary
}
}
And where I am calling the function within viewDidLoad:
setBarButton(image: #imageLiteral(resourceName: "settings-icon"), position: .right, target: self, selector: #selector(openSettings))
This only happens for UIBarButtonItem where an image is being set, not those with just a title or custom view

The title of your question was misleading but after reading your question I realized it was the same problem I had on one of my projects.
I was setting the barButtonItem title through code and when I changed it from:
navigationItem.leftBarButtonItem?.title = ""
To:
navigationItem.leftBarButtonItem?.title = nil
The problem disappeared.
I almost lost a entire day to fix this.
I hope this solves the problem for you.

Related

How to set a Custom image programmatically to and UIBarButtonItem

I am having a problem assigning a custom image to an UIBarButtonItem, the main problem is that the image appears as an white square when create the button.
here is my code:
fileprivate func configureNavigationBar() {
tabBarController?.navigationItem.title = lot.name
let exportImg: UIImage = UIImage(named: "action.png")!
let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(showCreationView(_:)))
let exportByEmail = UIBarButtonItem(image: exportImg, style: .done, target: self, action: #selector(exportDataByEmail(_:)))
tabBarController?.navigationItem.rightBarButtonItems = [exportByEmail,addButton]
}
The problem is with the exportByEmail, image is in the variable exportImg added from my assets:
The result obtained from my code:
Your image's background must be transparent, and you can set always original rendering mode to image, to display without changes as following
let exportByEmail = UIBarButtonItem(image: exportImg.withRenderingMode(.alwaysOriginal), style: .done, target: self, action: #selector(exportDataByEmail(_:)))

filterBarButton?.value(forKey: "view") is nil

Question
Using breakpoints, I found that filterBarButton is not nil, but the filterBarButton?.value(forKey: "view")is nil. The filterBarButton should have a view because I assigned it to a button in the viewDidLoad. Why is this happening? How do I fix this?
I use the frame of right bar button (the Filter button) to place the triangle image underneath it as shown below. I want the triangle image to be centered and directly underneath the Filter button.
Code
override func viewDidLoad() {
let filterButton = UIBarButtonItem(title: "Filter", style: .plain, target: self, action: #selector(filterButtonTapped))
navigationController?.navigationBar.topItem?.rightBarButtonItem = filterButton
setUpFilter()
}
func setUpFilter() {
let filterBarButton = navigationController?.navigationBar.topItem?.rightBarButtonItem
let btnView = filterBarButton?.value(forKey: "view") as AnyObject
}
Reference

Increase NavigationBar height

I have the following code:
func navbarbutton() {
UIView.animateWithDuration(0.2, animations: { () -> Void in
let current = self.navigationController?.navigationBar.frame
self.navigationController?.navigationBar.frame = CGRectMake(self.frame!.origin.x, self.frame!.origin.y, self.frame!.size.width, current!.size.height + 50)
self.navigationController?.navigationBar.layoutIfNeeded()
})
}
I'm able to increase the height of the navigation bar by 50 dp. That's not the issue for me. The issue I'm having is that the UIBarButtonItems are all aligned to the bottom. How can I get them aligned to the top so that I can add more to the bottom myself? I'm getting something as per the image:
Is it possible to get it aligned to the top?
Unfortunately you can't do that.
The view hierarchy within the UINavigationBar is private so you can't manipulate it without iterating over the subviews and going all hacky with it. This probably isn't a good idea.
Out of curiosity I looked at the Messages app in iOS 10 using the view debugger because they obviously do this. They actually achieve the layout by adding their own UIButton to replace the back and rightBarButtonItem. This is something you would be able to do however they also set the alpha of one of the internal (and private) content views to zero so that the original content is no longer visible.
This is something that you won't be able to do so easily unfortunately. You could try to hack things about until it works but remember you also need to handle pushes/pops, in call status bars, interactive transitions and rotation events.
If however you wasn't going for the iMessage style and just wanted to add some content underneath your navigation bar, why not look at pinning a UIVisualEffectView to the topLayoutGuide in your UIViewController? You can get a fairly nice look pretty easily and it saves hacking stuff about a lot. Here's an example:
Try this code:
Note: Code tested in Swift 3.
Answer 1: Updated Answer
class ViewController: UIViewController {
var customBar: UINavigationBar = UINavigationBar()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//Title
title = "Some Title"
// Add bar button item
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", style: .plain, target: self, action: #selector(addTapped))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(addTapped))
self.customBar.frame = CGRect(x:0, y:0, width:view.frame.width, height:(navigationController?.navigationBar.frame.height)! + 50)
self.customBar.backgroundColor = UIColor.green
self.view.addSubview(customBar)
}
func addTapped() {
print("Button Pressed")
}
Output:
Answer 2:
override var isViewLoaded: Bool {
// Add bar button item
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", style: .plain, target: self, action: #selector(addTapped))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(addTapped))
//Vertical and Horizonal barButtonItem position offset
navigationItem.leftBarButtonItem?.setTitlePositionAdjustment(UIOffset(horizontal: 0, vertical: 20), for: UIBarMetrics.default)
navigationItem.rightBarButtonItem?.setTitlePositionAdjustment(UIOffset(horizontal: 0, vertical: 20), for: UIBarMetrics.default)
return true
}
func addTapped() {
print("Button Pressed")
}
Note: Above code only works in isViewLoaded: Bool method.But, No luck.When, I tried this code in other viewLoad method.
Output 1: barButtonItem moved 20 pixel up vertically.
Output 2: barButtonItem moved 20 pixel down vertically.
Hope, Above code fix your problem.

Previous and Next keyboard buttons using UITextfields on Static UITableView

I am using a UITableView with static cells to show a form with several UITextFields (each with a unique ordered tag from 9000 to 9015).
When i select a UITextField, the keyboard shows up with a UIToolbar that has 2 buttons, previous and next. The buttons work fine as long as the previous or next UITextField is drawn on screen, otherwise i can not select it because viewWithTag can't find the Field.
DEMO: http://s15.postimg.org/5xjsoiupl/ezgif_com_video_to_gif.gif
EDIT: I tryed using IQKeyboardManagerbut it has the same bug. If the cells are not visible then they are not detected so the next or previous arrow is disabled...
UITextFields
let numberToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.frame.size.width, 50))
numberToolbar.barStyle = UIBarStyle.Default
numberToolbar.tintColor = color_green
prev_keyboard_button = UIBarButtonItem(title: "Previous", style: UIBarButtonItemStyle.Plain, target: self, action: "keyboardPrevButtonTapped:")
next_keyboard_button = UIBarButtonItem(title: "Next", style: UIBarButtonItemStyle.Plain, target: self, action: "keyboardNextButtonTapped:")
numberToolbar.items = [
prev_keyboard_button,
next_keyboard_button,
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "OK", style: UIBarButtonItemStyle.Plain, target: self, action: "keyboardOKButtonTapped:")]
numberToolbar.sizeToFit()
// bind vars
var_input_name.inputAccessoryView = numberToolbar
var_input_name.delegate = self
var_input_name.tag = 9000 // 9000 + index (0,1,2,3,..)
...
Previous and next code:
func textFieldDidBeginEditing(textField: UITextField) {
// current tag
current_input_tag = textField.tag
// check if it is the first
prev_keyboard_button.enabled = !(textField.tag == 9000)
// check if it is the last
next_keyboard_button.enabled = !(textField.tag == 9015)
}
func keyboardPrevButtonTapped(sender: UIBarButtonItem) {
if current_input_tag > 9000 {
// find next input
if let input = self.view.viewWithTag(current_input_tag - 1) as? UITextField {
input.becomeFirstResponder()
}
}
}
func keyboardNextButtonTapped(sender: UIBarButtonItem) {
if current_input_tag < 9015 {
// find next input
if let input = self.view.viewWithTag(current_input_tag + 1) as? UITextField {
input.becomeFirstResponder()
}
}
}
Is there a way to always draw the static cells or should i be implementing this differently?
if the sell is out of the screen it will be released. It's no matter if you use static or dynamic cells. Probably views you try to find is not exists at this moment

How to add / use default icons to navigation bar

I want to use some of default iOS icons i.e.
in navigation bar.
Basically I don't know how to call image of that item (directly from native library - I know how to download it and place as custom image:)):
var myButton:UIButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
myButton.addTarget(self, action: "reload", forControlEvents: UIControlEvents.TouchUpInside)
myButton.setImage(???, forState: <#UIControlState#>)
You can use UIBarButtonSystemItem this way:
let button = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Refresh, target: self, action: "someAction")
navigationItem.leftBarButtonItem = button
Result for leftBarButtonItem:
If you want to set it at right side you can use this code:
navigationItem.rightBarButtonItem = button
Result for rightBarButtonItem:
Swift: These are the most commonly used options:
To Use custom image with original colour:
let customImageBarBtn1 = UIBarButtonItem(
UIImage(named: "someImage.png").withRenderingMode(.alwaysOriginal),
style: .plain, target: self, action: #selector(handleClick))
To Use custom image with tint colour:
let customImageBarBtn2 = UIBarButtonItem(
UIImage(named: "someImage.png").withRenderingMode(.alwaysTemplate),
style: .plain, target: self, action: #selector(handleClick))
Or use system provided buttons:
let systemBarBtn = UIBarButtonItem(
barButtonSystemItem: .search,
target: self, action: #selector(handleClick))
Then add any one of these buttons to the navigationItem:
navigationItem.leftBarButtonItems = [customImageBarBtn1, customImageBarBtn2]
navigationItem.rightBarButtonItems = [systemBarBtn]
// OR you can use this if there's only one item.
navigationItem.rightBarButtonItem = systemBarBtn
For custom Images: As a starting size, 22ptx22pt images work well for the default iPhone Navigation Bar size.
In swift 4.3
let btnRefresh = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.refresh, target: self, action: #selector(targeted function to invoke))
//If you want icon in left side
navigationItem.leftBarButtonItem = btnRefresh
//If you want icon in right side
navigationItem.rightBarButtonItem = btnRefresh

Resources