Vertically align bar buttons inside toolbar - swift

I am currently using the following code to display a datepicker when a user clicks on a UITextfield. This works fine, but the problem is there left and right button are not properly vertically center aligned. Is there any way to accomplish this? I tried using UIOffset on the buttons but without result.
private func setupDatePicker() {
let toolBar = UIToolbar(frame: CGRect(x: 0, y: self.view.frame.size.height/6,
width: self.view.frame.size.width, height: 40.0))
toolBar.layer.position = CGPoint(x: self.view.frame.size.width/2, y: self.view.frame.size.height-20.0)
toolBar.barStyle = UIBarStyle.blackTranslucent
toolBar.tintColor = UIColor.white
toolBar.backgroundColor = UIColor.black
let cancelBtn = UIBarButtonItem(title: "cancel".localized(lang: Localize.currentLanguage()), style: UIBarButtonItemStyle.plain, target: self,
action: #selector(tapppedToolBarBtn))
let okBarBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self,
action: #selector(donePressed))
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace,
target: self, action: nil)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width / 3,
height: self.view.frame.size.height))
label.font = UIFont(name: "Roboto-Regular", size: 12)
label.backgroundColor = UIColor.clear
label.textColor = UIColor.white
label.text = "selectdate".localized(lang: Localize.currentLanguage())
label.textAlignment = NSTextAlignment.center
let textBtn = UIBarButtonItem(customView: label)
toolBar.setItems([cancelBtn, flexSpace, textBtn, flexSpace, okBarBtn], animated: true)
startDateTxf.inputAccessoryView = toolBar
}
The result :
Result of the datepicker toolbar

I managed to fix this alignment issue by using the following code :
let toolBar = UIToolbar(frame: CGRect(x: 0, y: self.view.frame.size.height/6,
width: self.view.frame.size.width, height: 40.0))
toolBar.layer.position = CGPoint(x: self.view.frame.size.width/2, y: self.view.frame.size.height-20.0)
toolBar.barStyle = UIBarStyle.blackTranslucent
toolBar.tintColor = UIColor.white
toolBar.backgroundColor = UIColor.black
let cancelBtn1 = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width / 4,
height: self.view.frame.size.height))
cancelBtn1.setTitle("cancel".localized(lang: Localize.currentLanguage()), for: .normal)
cancelBtn1.addTarget(self, action: #selector(tapppedToolBarBtn), for: .touchUpInside)
let cancelBtn = UIBarButtonItem(customView: cancelBtn1)
let okBarBtn1 = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width / 4,
height: self.view.frame.size.height))
okBarBtn1.setTitle("Done", for: .normal)
okBarBtn1.addTarget(self, action: #selector(donePressed(sender:)), for: .touchUpInside)
let okBarBtn = UIBarButtonItem(customView: okBarBtn1)
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace,
target: self, action: nil)
let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width / 3,
height: self.view.frame.size.height))
label.font = UIFont(name: "Roboto-Regular", size: 12)
label.backgroundColor = UIColor.clear
label.textColor = UIColor.white
label.text = "selectdate".localized(lang: Localize.currentLanguage())
label.textAlignment = NSTextAlignment.center
let textBtn = UIBarButtonItem(customView: label)
toolBar.setItems([cancelBtn, flexSpace, textBtn, flexSpace, okBarBtn], animated: true)
startDateTxf.inputAccessoryView = toolBar
The result is : result in simulator

Related

How to change UITextField RightView size?

I trying put to 2 items in rightView component. for example;`
let label = UILabel(frame: CGRect(x: -80, y: 0, width: 100, height: 50))
let rightView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 100))
label.text = String(self.availableBalance) + " ₺"
label.textColor = Colors.INVEST_RED
label.textAlignment = .center
let imageView = UIImageView(frame: CGRect(x: -100, y: 15, width: 20, height: 20))
imageView.image = UIImage(named: "full_balance_button")
rightView.addSubview(imageView)
rightView.addSubview(label)
let tap = UITapGestureRecognizer(target: self, action:#selector(tapGesture))
label.addGestureRecognizer(tap)
label.isUserInteractionEnabled = true
imageView.addGestureRecognizer(tap)
imageView.isUserInteractionEnabled = true
rightView.addGestureRecognizer(tap)
rightView.isUserInteractionEnabled = true
rightView.backgroundColor = .white
textField.rightView = rightView
textField.rightViewMode = .always
But I can't change size rightView.

How to create overlapped bar button item programatically

I know how to create overlap shopping cart and quantity label with xib using uiimage like this
Now i'm trying to create overlap bar button items programatically but cannot figure out how to position the elements. My attempt:
My current code for bar button items:
let button: UIButton = UIButton(frame: CGRect(x: 0.0,
y: 0.0,
width: 24.0,
height: 24.0))
button.setImage(UIImage(named: "my cart", in: nil, compatibleWith: nil), for: .normal)
button.addTarget(self, action: #selector(cartButtonDidTapped), for: .touchUpInside)
let shoppingCartButton: UIBarButtonItem = UIBarButtonItem(customView: button)
shoppingCartQuantityLabel.layer.cornerRadius = 10
shoppingCartQuantityLabel.layer.masksToBounds = true
shoppingCartQuantityLabel.textColor = .white
shoppingCartQuantityLabel.backgroundColor = .red
shoppingCartQuantityLabel.textAlignment = .center
let shoppingCartQuantityLabelItem: UIBarButtonItem = UIBarButtonItem(customView: shoppingCartQuantityLabel)
navigationItem.rightBarButtonItems = [shoppingCartQuantityLabelItem, shoppingCartButton]
Idea here is to add the label as subview inside the button. You can adjust the label as per your needs from the below example,
let button: UIButton = UIButton(frame: CGRect(x: 0.0, y: 0.0, width: 24.0, height: 24.0))
button.setImage(#imageLiteral(resourceName: "my cart"), for: .normal)
let label = UILabel(frame: .init(origin: .init(x: 20, y: -8), size: .init(width: 20, height: 20)))
label.text = "12"
label.textAlignment = .center
label.textColor = .white
label.font = .systemFont(ofSize: 10)
label.backgroundColor = .red
label.layer.cornerRadius = 10
label.clipsToBounds = true
button.addSubview(label)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
You can use this code snippet also from Github: https://gist.github.com/freedom27/c709923b163e26405f62b799437243f4#gistcomment-2236010
then set badge to your last right bar button item as below
navigationItem.rightBarButtonItems = [shoppingCartButton]
let lastBarButton = navigationItem.rightBarButtonItems?.last
lastBarButton?.setBadge(text: "10", withOffsetFromTopRight: CGPoint(x: 38, y: -3), andColor: UIColor.red, andFilled: true, andFontSize: 12)

Done Toolbar on UIPickerView

So I have a button on a page when clicked I am opening up a picker view. I have populated the picker view with the months. I added a toolbar but whenever I try to select it just scrolls the picker view to the top.
monthPicker = UIPickerView(frame: CGRect(x: 0, y: self.view.frame.size.height- monthPicker.frame.size.height, width: self.view.frame.size.width, height: monthPicker.frame.size.height))
monthPicker.delegate = self
monthPicker.dataSource = self
monthpickerData = ["January","February","March","April","May","June","July","August","September","October","November","December"]
monthPicker.backgroundColor = UIColor.white
//
let btnDone = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.monthdoneButtonAction))
let barAccessory = UIToolbar(frame: CGRect(x: 0, y: 0, width: monthPicker.frame.size.width, height: 44))
barAccessory.barStyle = .default
barAccessory.isTranslucent = false
barAccessory.items = [flexiblespace,btnDone]
monthPicker.addSubview(barAccessory)
It seems like UIPickerView is not letting its children receive touch events. If you are showing this in conjunction with UITextField you can use it's inputView and inputAccessoryView to acheive the same. Alternatively you can create a top level container UIView to hold both toolbar and picker view like this:
let picker = UIView(frame: CGRect(x: 0, y: view.frame.height - 260, width: view.frame.width, height: 260))
// Toolbar
let btnDone = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(self.monthdoneButtonAction))
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(self.cancelClick))
let barAccessory = UIToolbar(frame: CGRect(x: 0, y: 0, width: picker.frame.width, height: 44))
barAccessory.barStyle = .default
barAccessory.isTranslucent = false
barAccessory.items = [cancelButton, spaceButton, btnDone]
picker.addSubview(barAccessory)
// Month UIPIckerView
monthPicker = UIPickerView(frame: CGRect(x: 0, y: barAccessory.frame.height, width: view.frame.width, height: picker.frame.height-barAccessory.frame.height))
monthPicker.delegate = self
monthPicker.dataSource = self
monthpickerData = ["January","February","March","April","May","June","July","August","September","October","November","December"]
monthPicker.backgroundColor = UIColor.white
picker.addSubview(monthPicker)

UIPickerView : Toolbar is not visible on UIPickerView

function pickerView() Code called on ViewLoad
private func createPickerView(){
picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: view.frame.width,height: 300))
picker.showsSelectionIndicator = true
picker.delegate = self
picker.dataSource = self
let toolBar = UIToolbar.init(frame: CGRect(x: 0, y: self.view.frame.size.height -
picker.frame.size.height-50, width: view.frame.width,height: 50))
toolBar.barStyle = UIBarStyle.default
toolBar.tintColor = UIColor(red:14.0/255, green:122.0/255, blue:254.0/255, alpha: 1)
toolBar.sizeToFit()
// TODO need to update actions for all buttons
let spaceButton = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem.init(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(self.pickerDoneAction))
toolBar.setItems([spaceButton, doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
senderIdLabel.inputView = picker
senderIdLabel.inputAccessoryView = toolBar
}
Your pickerView height is the prob and no need to set from for Toolbar.Try like this it is working
let picker = UIPickerView(frame: CGRect(x: 0, y: 0, width: view.frame.width,height: 215))
picker.showsSelectionIndicator = true
picker.delegate = self
picker.dataSource = self
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.tintColor = UIColor(red:14.0/255, green:122.0/255, blue:254.0/255, alpha: 1)
toolBar.sizeToFit()

UIToolbar left and right spacing when rotating device in IOS11

I'm having a strange issue with the padding of the UIToolbar since iOS11. When the device is rotated the left and right padding of the toolbar gets bigger(watch example below).
It doesn't matter if the device is in portrait or landscape mode before the rotation. The extra spacing only occurs after rotating. I think it's an auto resizing issue or something.
View Debugger before rotation (correct spacing):
https://www.dropbox.com/s/1wigv1et88t1mvn/Schermafdruk%202018-01-31%2015.51.05.png?dl=0
View Debugger after rotation (wrong spacing):
https://www.dropbox.com/s/9gnqi6hzv5czcnw/Schermafdruk%202018-01-31%2020.59.48.png?dl=0
Example:
https://www.dropbox.com/s/s7jbmbsuorump5e/spacing-toolbar.gif?dl=0
I'm using a toolbar class to create the buttons inside the toolbar.
In the xcode interface the option 'Autoresize Subview' is checked.
Code:
class ToolbarClass: UIToolbar {
//Set height of toolbar
override func sizeThatFits(_ size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
size.height = 60
return size
}
//Toolbar settings
override func layoutSubviews() {
super.layoutSubviews()
//Default
self.barStyle = UIBarStyle.default
self.sizeToFit()
//Buttons ios11+
//Space
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceBetween:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
spaceBetween.width = 1.0
let nameSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
nameSpace.width = 10
//Logo
let logoImage = UIImage(named: "MBS-Logo")
let logoImageView = UIImageView(image: logoImage)
logoImageView.frame = CGRect(x: -46, y: 0, width: 48, height: 54)
logoImageView.contentMode = .scaleAspectFit
let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 54))
logoView.clipsToBounds = false
logoView.layer.cornerRadius = logoView.frame.width / 2
logoView.addSubview(logoImageView)
let logoImg = UIBarButtonItem(customView: logoView)
logoImg.customView = logoView
//Profile
let profileImage = UIImage(named: "No-Profile")
let profileImageView = UIImageView(image: profileImage)
profileImageView.frame = CGRect(x: 40, y: 0, width: 50, height: 50)
profileImageView.contentMode = .scaleAspectFit
profileImageView.clipsToBounds = true
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
let profileView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
profileView.clipsToBounds = false
profileView.addSubview(profileImageView)
let profileImg = UIBarButtonItem(customView: profileView)
profileImg.customView = profileView
//NameLabel
let nameLbl = UILabel()
nameLbl.frame = CGRect(x: 0, y: 0, width: 200, height: 60)
nameLbl.text = "Hi"
nameLbl.font = UIFont(name: "Roboto", size: 22)
nameLbl.textColor = UIColor.white
let nameLabel = UIBarButtonItem()
nameLabel.customView = nameLbl
//Settings
let settingsBtn = UIButton()
settingsBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
settingsBtn.addTarget(self, action: #selector(self.settingsPressed), for: .touchUpInside)
let settingsButton = UIBarButtonItem()
settingsButton.customView = settingsBtn
//Classes
let classesBtn = UIButton()
classesBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
classesBtn.addTarget(self, action: #selector(self.classesPressed), for: .touchUpInside)
let classesButton = UIBarButtonItem()
classesButton.customView = classesBtn
//Set buttons
self.setItems([profileImg, logoImg, nameSpace, nameLabel, spaceButton, classesButton, spaceBetween, settingsButton], animated: false)
}
}
First of all layoutSubviews is not the right place to add all the items. For example every time device orientate layoutSubviews is called and all items will be created again. Use init?(coder:) or init(frame:).
Once you move your code to init?(coder:) or init(frame:) you will see the left and right margin (currently it appears only when you orientate). This is actual behaviour of UIToolBar, It adds margin on both sides automatically.
To remove that margin just add negative separator of fixed size on start and end of toolbar items.
let negativeFizedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeFizedSpace.width = -20 // Spacing 20 for iPad and 16 for iPhone
class ToolbarClass: UIToolbar {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
//Space
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceBetween:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
spaceBetween.width = 1.0
let nameSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
nameSpace.width = 10
//Logo
let logoImage = UIImage(named: "MBS-Logo")
let logoImageView = UIImageView(image: logoImage)
logoImageView.frame = CGRect(x: -46, y: 0, width: 48, height: 54)
logoImageView.contentMode = .scaleAspectFit
let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 54))
logoView.clipsToBounds = false
logoView.layer.cornerRadius = logoView.frame.width / 2
logoView.addSubview(logoImageView)
let logoImg = UIBarButtonItem(customView: logoView)
logoImg.customView = logoView
//Profile
let profileImage = UIImage(named: "No-Profile")
let profileImageView = UIImageView(image: profileImage)
profileImageView.frame = CGRect(x: 40, y: 0, width: 50, height: 50)
profileImageView.contentMode = .scaleAspectFit
profileImageView.clipsToBounds = true
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
let profileView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
profileView.clipsToBounds = false
profileView.addSubview(profileImageView)
let profileImg = UIBarButtonItem(customView: profileView)
profileImg.customView = profileView
//NameLabel
let nameLbl = UILabel()
nameLbl.frame = CGRect(x: 0, y: 0, width: 200, height: 60)
nameLbl.text = "Hi"
nameLbl.font = UIFont(name: "Roboto", size: 22)
nameLbl.textColor = UIColor.white
let nameLabel = UIBarButtonItem()
nameLabel.customView = nameLbl
//Settings
let settingsBtn = UIButton()
settingsBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
settingsBtn.addTarget(self, action: #selector(self.settingsPressed), for: .touchUpInside)
let settingsButton = UIBarButtonItem()
settingsButton.customView = settingsBtn
//Classes
let classesBtn = UIButton()
classesBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
classesBtn.addTarget(self, action: #selector(self.classesPressed), for: .touchUpInside)
let classesButton = UIBarButtonItem()
classesButton.customView = classesBtn
let negativeFizedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeFizedSpace.width = -20 // Spacing 20 for iPad and 16 for iPhone
//Set buttons
self.setItems([negativeFizedSpace, profileImg, logoImg, nameSpace, nameLabel, spaceButton, classesButton, spaceBetween, settingsButton, negativeFizedSpace], animated: false)
}
//Set height of toolbar
override func sizeThatFits(_ size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
size.height = 60
return size
}
}
UPDATE
If using Navigation Controller Toolbar. Alternate is to create a UIViewController extension to add generic toolbar items and call that in viewDidLoad method of your ViewController.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addGeneralToolbarItems()
}
}
class ToolbarClass: UIToolbar {
//Set height of toolbar
override func sizeThatFits(_ size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
size.height = 60
return size
}
}
extension UIViewController {
func addGeneralToolbarItems() {
//Space
let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceBetween:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
spaceBetween.width = 1.0
let nameSpace:UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
nameSpace.width = 10
//Logo
let logoImage = UIImage(named: "MBS-Logo")
let logoImageView = UIImageView(image: logoImage)
logoImageView.frame = CGRect(x: -46, y: 0, width: 48, height: 54)
logoImageView.contentMode = .scaleAspectFit
let logoView = UIView(frame: CGRect(x: 0, y: 0, width: 48, height: 54))
logoView.clipsToBounds = false
logoView.layer.cornerRadius = logoView.frame.width / 2
logoView.addSubview(logoImageView)
let logoImg = UIBarButtonItem(customView: logoView)
logoImg.customView = logoView
//Profile
let profileImage = UIImage(named: "No-Profile")
let profileImageView = UIImageView(image: profileImage)
profileImageView.frame = CGRect(x: 40, y: 0, width: 50, height: 50)
profileImageView.contentMode = .scaleAspectFit
profileImageView.clipsToBounds = true
profileImageView.layer.cornerRadius = profileImageView.frame.width / 2
let profileView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
profileView.clipsToBounds = false
profileView.addSubview(profileImageView)
let profileImg = UIBarButtonItem(customView: profileView)
profileImg.customView = profileView
//NameLabel
let nameLbl = UILabel()
nameLbl.frame = CGRect(x: 0, y: 0, width: 200, height: 60)
nameLbl.text = "Hi"
nameLbl.font = UIFont(name: "Roboto", size: 22)
nameLbl.textColor = UIColor.white
let nameLabel = UIBarButtonItem()
nameLabel.customView = nameLbl
//Settings
let settingsBtn = UIButton()
settingsBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
settingsBtn.setImage(UIImage(named: "Settings-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
settingsBtn.addTarget(self, action: #selector(self.settingsPressed), for: .touchUpInside)
let settingsButton = UIBarButtonItem()
settingsButton.customView = settingsBtn
//Classes
let classesBtn = UIButton()
classesBtn.frame = CGRect(x: 0, y: 0, width: 64, height: 60)
classesBtn.setImage(UIImage(named: "Classes-Bar")?.withRenderingMode(.alwaysOriginal), for: .normal)
classesBtn.addTarget(self, action: #selector(self.classesPressed), for: .touchUpInside)
let classesButton = UIBarButtonItem()
classesButton.customView = classesBtn
let negativeFizedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
negativeFizedSpace.width = -20 // Spacing 20 for iPad and 16 for iPhone
//Set buttons
self.setToolbarItems([negativeFizedSpace, profileImg, logoImg, nameSpace, nameLabel, spaceButton, classesButton, spaceBetween, settingsButton, negativeFizedSpace], animated: false)
}
#objc func settingsPressed() {
}
#objc func classesPressed() {
}
}