iOS: adding buttons to Toolbar programmatically - swift

I need to create Toolbar and add buttons programmatically. I will have different sets of buttons for diferent screens.
That's easy.
Also, I need to center those buttons. They should have equal space between them.
And also I need that all those buttons separate screen width only between themselfs. Like, I have 5 buttons, total screen width is 300, so each button will have width 60. I am not sure how to do that, i tried dirrenrt things but they wasn't centered or hadn't such width. Any ideas how to do that?
class OptionsView: UIView {
#IBOutlet weak var toolbar: UIToolbar!
var width: CGFloat {
return 0//UIScreen.main.bounds.width/5 //was trying to calculate width , but it did not work
}
override func awakeFromNib() {
super.awakeFromNib()
toolbar.isTranslucent = true
toolbar.setBackgroundImage(UIImage(), forToolbarPosition: UIBarPosition.any, barMetrics: UIBarMetrics.default)
toolbar.setShadowImage(UIImage(), forToolbarPosition: UIBarPosition.any)
toolbar.barTintColor = .white
backgroundColor = .clear
}
func addAirPlay(target: Any?, action: Selector) {
let normalImage = UIImage(named: "player-airplay")
let button = UIButton(type: .custom)
button.frame = CGRect(x: 0, y: 0, width: width, height: 100)
button.setImage(normalImage, for: UIControlState())
button.addTarget(target, action: action, for: .touchUpInside)
let item = UIBarButtonItem(customView: button)
//item.width = width //was trying to play with that
var items = toolbar.items
items?.append(item)
toolbar.items = items
toolbar.reload()
}
func addOrientation(target: Any?, action: Selector) {
let button = UIButton(type: .custom)
button.tag = orientationTag
button.frame = CGRect(x: 0, y: 0, width: width, height: 100)
button.addTarget(target, action: action, for: .touchUpInside)
let item = UIBarButtonItem(customView: button)
//item.width = width
var items = toolbar.items
items?.append(item)
toolbar.items = items
toolbar.reload()
reloadOrientation()
}
func addFlexibleSpace() {
let item = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
var items = toolbar.items
items?.append(item)
toolbar.items = items
toolbar.reload()
}
Creating:
optionsView = OptionsView.loadFromNib()
playerView.addSubview(optionsView)
optionsView.snp.makeConstraints { (make) in
make.leading.trailing.top.bottom.equalTo(self.optionsPlaceholderView)
}
// optionsView.addFlexibleSpace() //was trying that as well
optionsView.addAirPlay(target: self, action: #selector(airplayButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addOrientation(target: self, action: #selector(orientationButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addFave(target: self, action: #selector(faveButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addExtra(target: self, action: #selector(showExtraButtonAction(_:)))
optionsView.addFlexibleSpace()
optionsView.addScenes(target: self, action: #selector(sceneButtonAction(_:)))
// optionsView.addFlexibleSpace()

Related

UIToolbar doesn't show again in view when dismissing keyboard in Swift

I have an UIToolbar containing a UITextField. I want to show the toolbar above the keyboard and then display it again when I finish editing inside the textfield.
The issue is that it is working when selecting the textfield. However, the toolbar is disappearing from the view when hiding the keyboard.
What should be done to redisplay it again to my view?
My Swift code is:
Add UITextFieldDelegate
class ATCChatThreadViewController: MessagesViewController, MessagesDataSource, MessageInputBarDelegate, UITextFieldDelegate {
Create ToolBar is as below
func createToolbar(){
//Fixed space
let fixed = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: self, action: nil)
fixed.width = 10
//Camera
//let img = UIImage(named: "camera-filled-icon")!.withRenderingMode(UIImage.RenderingMode.alwaysOriginal)
let img = UIImage.localImage("camera-filled-icon", template: true)
let iconSize = CGRect(origin: CGPoint.zero, size: CGSize(width: 30, height: 30))
let iconButton = UIButton(frame: iconSize)
iconButton.setTitleColor(uiConfig.primaryColor, for: .normal)
iconButton.setBackgroundImage(img, for: .normal)
let cameraItem = UIBarButtonItem(customView: iconButton)
cameraItem.tintColor = uiConfig.primaryColor
iconButton.addTarget(self, action: #selector(cameraButtonPressed), for: .touchUpInside)
//TextField true
textFieldChat = UITextField(frame: CGRectMake(0,0,(self.view.frame.size.width - 100) ,30))
textFieldChat.tintColor = uiConfig.primaryColor
textFieldChat.textColor = uiConfig.inputTextViewTextColor
textFieldChat.backgroundColor = uiConfig.inputTextViewBgColor
textFieldChat.layer.cornerRadius = 14.0
textFieldChat.layer.borderWidth = 0.0
textFieldChat.font = UIFont.systemFont(ofSize: 16.0)
textFieldChat.delegate = self
textFieldChat.attributedPlaceholder = NSAttributedString(string: "Start typing...".localized(), attributes: [NSAttributedString.Key.foregroundColor: uiConfig.inputPlaceholderTextColor])
let paddingView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 20))
textFieldChat.leftView = paddingView
textFieldChat.leftViewMode = .always
let textFieldButton = UIBarButtonItem(customView: textFieldChat)
//Fixed space
let fixedTwo = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: self, action: nil)
fixedTwo.width = 10
//Send Button
let imgSend = UIImage.localImage("share-icon", template: true)
let iconSendSize = CGRect(origin: CGPoint.zero, size: CGSize(width: 30, height: 30))
let sendButton = UIButton(frame: iconSendSize)
sendButton.setTitleColor(uiConfig.primaryColor, for: .normal)
sendButton.setBackgroundImage(imgSend, for: .normal)
let sendItem = UIBarButtonItem(customView: sendButton)
sendItem
.tintColor = uiConfig.primaryColor
sendButton.addTarget(self, action: #selector(sendBtnPressedWith), for: .touchUpInside)
//Flexible Space
// let flexible = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil)
let flexible = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: self, action: nil)
flexible.width = 10
//Toolbar
var bottomsafeAreaHeight: CGFloat?
if #available(iOS 11.0, *) {
bottomsafeAreaHeight = UIApplication.shared.windows.first{$0.isKeyWindow }?.safeAreaInsets.bottom ?? 0
} else {
// Fallback on earlier versions
bottomsafeAreaHeight = bottomLayoutGuide.length
bottomsafeAreaHeight = UIApplication.shared.keyWindow?.rootViewController?.bottomLayoutGuide.length ?? 0
}
toolbar = UIToolbar(frame: CGRectMake(0,(self.view.frame.size.height - 116 - (bottomsafeAreaHeight ?? 0)),view.frame.width,50))
toolbar.sizeToFit()
toolbar.barTintColor = UIColor.f5f5f5ColorBg()
toolbar.isTranslucent = false
toolbar.tintColor = uiConfig.primaryColor
toolbar.items = [fixed, cameraItem, fixed, textFieldButton,fixedTwo, sendItem,flexible]
view.addSubview(toolbar)
}
// MARK: - UITextFieldDelegate
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
textFieldChat.inputAccessoryView = toolbar
return true
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
view.addSubview(toolbar)
self.toolbar.isHidden = false
return true
}
if only chat etxfield is using toolbar then replace line:
view.addSubview(toolbar)
with
textFieldChat.inputAccessoryView = toolbar
remove both methods textFieldShouldBeginEditing and textFieldShouldEndEditing

How to add UIImageView to navigation bar in swift?

I have this code that adds a rounded border around a UIImage using UIImageView and I've used UITapGestureRecognizer to let the user tap on the button:
var profilePicture = UIImageView()
func setupUserProfileButton() {
let defaultPicture = UIImage(named: "profilePictureSmall")
profilePicture = UIImageView(image: defaultPicture)
profilePicture.layer.cornerRadius = profilePicture.frame.width / 2
profilePicture.clipsToBounds = true
profilePicture.layer.borderColor = UIColor.black.cgColor
profilePicture.layer.borderWidth = 1
// Letting users click on the image
profilePicture.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(profilePictureTapped))
profilePicture.addGestureRecognizer(tapGesture)
}
How can I add this to the left side of a navigation bar? Is it possible? And I don't think the tap gesture is needed if I can add the ImageView to the navigation bar as a barButtonItem, so you can ignore that. I kinda found some similar questions but they were in objective C and none of what I tried worked.
Here is what I came up with based on an answer:
import UIKit
import Firebase
class CreateStoryPage: BaseAndExtensions {
let userProfileButton = UIButton(type: .custom)
override func viewDidLoad() {
super.viewDidLoad()
// Call all the elements
setupUserProfileButton()
}
// MARK:- Setups
// Setup the user profile button
func setupUserProfileButton() {
userProfileButton.setImage(#imageLiteral(resourceName: "profilePictureSmall.png"), for: .normal)
userProfileButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
userProfileButton.addTarget(self, action: #selector(profilePictureTapped), for: .touchUpInside)
let userProfileView = UIView(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
userProfileView.layer.cornerRadius = 14
userProfileView.backgroundColor = .red
userProfileView.addSubview(userProfileButton)
let leftNavBarItem = UIBarButtonItem(customView: userProfileView)
self.navigationItem.setLeftBarButton(leftNavBarItem, animated: true)
}
// if user taps on profile picture
#objc func profilePictureTapped() {
let userProfilePage = UserProfilePage()
present(userProfilePage, animated: true, completion: nil)
}
}
Try this;
private func setupRightItem() {
let userProfileButton = UIButton(type: .custom)
userProfileButton.imageView?.contentMode = .scaleAspectFill
userProfileButton.clipsToBounds = true
userProfileButton.addTarget(self, action: #selector(profilePictureTapped), for: .touchUpInside)
userProfileButton.setImage(#imageLiteral(resourceName: "profilePictureSmall.png"), for: .normal)
userProfileButton.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: userProfileButton)
userProfileButton.widthAnchor.constraint(equalToConstant: 30).isActive = true
userProfileButton.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
#objc private func goProfile() {
/// -> Action
}
let navBtn = UIButton(type: .custom)
navBtn.setImage("yourImage", for: .normal)
navBtn.frame = CGRect(x: 0, y: 0, width: 28, height: 28)
navBtn.addTarget(self, action: #selector(self.openProfile(_:)), for: .touchUpInside)
let view = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 28))
view.cornerRadius = 14
view.backgroundColor = Global.colorBlue
view.addSubview(navBtn)
let leftNavBarItem = UIBarButtonItem(customView: view)
self.navigationItem.setLeftBarButton(leftNavBarItem, animated: true)
#objc
func openProfile(_ sender: UIButton) {
}

Swift hide back button

I need to hide back button and paste another button
self.navigationItem.setHidesBackButton(true, animated: false)
self.navigationItem.hidesBackButton = true
self.navigationController?.navigationItem.hidesBackButton = true
self.navigationController?.navigationBar.topItem?.hidesBackButton = true
self.tabBarController?.navigationController?.navigationItem.hidesBackButton = true
self.tabBarController?.navigationController?.navigationItem.setHidesBackButton(true, animated: false)
self.tabBarController?.navigationItem.hidesBackButton = true
let backButton1 = UIBarButtonItem (title: "Button", style: .plain, target: self, action: #selector(GoToBack))
self.navigationItem.leftBarButtonItem = backButton1
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(GoToBack))
self.tabBarController?.navigationItem.setLeftBarButtonItems([backButton1], animated: true)
but this code didnt work, back button dont hided or replaced to another button
how can i solve this problem ?
show this vc like this
self.navigationController?.pushViewController(viewcontroller, animated: true)
First, Create BaseViewController in your project and set backButton hide code and add custom back button code in viewDidLoad.
After that, all the controller of your project should inherit from BaseViewController so new back button enables for all controller.
BaseViewContorller
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
self.setBackButton()// Set Custom back button
}
Set Custom BackButton Code
//Add Custom Back Button
fileprivate func setBackButton() {
let button = UIButton(type: UIButton.ButtonType.custom) as UIButton
button.frame = CGRect(x: 0, y: 0, width: 44, height: 44)
button.contentHorizontalAlignment = .fill
button.contentVerticalAlignment = .fill
button.imageView?.contentMode = .center
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: -10, bottom: 0, right: 0)
button.setImage(UIImage(named: "backButton.png"), for: .normal)
button.addTarget(self, action: #selector(btnBackActionHandler(_:)), for:.touchUpInside)
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: button)
}
#objc func btnBackActionHandler(_ sender : AnyObject) {
self.navigationController?.popViewController(animated: true)
}
Use the below code
self.navigationItem.setHidesBackButton(true, animated:true);
addNavButtons()
//MARK:- NAVIGATION BUTTONS
func addNavButtons(){
let btn_back = UIButton(type: .custom)
btn_back.setImage(UIImage(named: "icon_back"), for: .normal)
btn_back.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
btn_back.addTarget(self, action: #selector(goBack), for: .touchUpInside)
btn_back.imageView?.contentMode = UIViewContentMode.scaleAspectFit
let menuitem1 = UIBarButtonItem(customView: btn_back)
self.navigationItem.setLeftBarButtonItems([menuitem1], animated: true)
let btn_search = UIButton(type: .custom)
btn_search.setImage(UIImage(named: "searchby_icon"), for: .normal)
btn_search.frame = CGRect(x: 0, y: 0, width: 30, height: 30)
btn_search.addTarget(self, action: #selector(SearchButtonClick), for: .touchUpInside)
btn_search.imageView?.contentMode = UIViewContentMode.scaleAspectFit
let menuitem2 = UIBarButtonItem(customView: btn_search)
self.navigationItem.setRightBarButtonItems([menuitem2], animated: true)
}
#objc func goBack(sender:UIButton!) {
_ = navigationController?.popViewController(animated: true)
}
#objc func SearchButtonClick(sender:UIButton!) {
}

UIToolbar with custom height

I'm trying trying to change my toolbar that I added Programmatically. but it didn't reflect. so any help
this is my code. and in the viewController I embed the view from UINavigation Controller
class ViewController: UIViewController,UIToolbarDelegate {
private var toolItems : [UIBarButtonItem] = []
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
navigationController?.isToolbarHidden = false
let height: CGFloat = 130
let bounds = self.navigationController?.toolbar.bounds
navigationController?.toolbar.barTintColor = UIColor(red: 0.0/42, green: 0.0/42, blue: 0.0/56, alpha: 1)
navigationController?.toolbar.tintColor = UIColor.white
navigationController?.toolbar.frame = CGRect(x: 0, y: self.view.frame.height - 80, width: self.view.frame.width, height: (bounds?.height)! + height)
navigationController?.toolbar.isTranslucent = false
navigationController?.toolbar.heightAnchor.constraint(equalToConstant: (bounds?.height)! + height).isActive = true
navigationController?.toolbar.sizeToFit()
let btn_Tracking = UIButton(type: .custom)
btn_Tracking.setImage(UIImage(named: "icon-trackingtabbed#2x"), for: .normal)
btn_Tracking.sizeToFit()
let trackingItem = UIBarButtonItem(customView: btn_Tracking)
///Sign
let btn_sign = UIButton(type: .custom)
btn_sign.setImage(UIImage(named: "icon-trackingtabbed#2x"), for: .normal)
btn_sign.sizeToFit()
let sginItem = UIBarButtonItem(customView: btn_sign)
let fixedSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.fixedSpace, target: nil, action: nil)
fixedSpace.width = 10.0
let flexibleSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
self.toolbarItems = [flexibleSpace,sginItem,flexibleSpace,trackingItem,flexibleSpace]
}
}

Back Button Image - what is it called in Swift?

I am trying to use Swift's internal back button image.
I have asked this question before and got the technically correct answer that it inherits it from the previous View, BUT if I insert this code you can control the back button on the current View.
// Takeover Back Button
self.navigationItem.hidesBackButton = false
let newBackButton = UIBarButtonItem(title: "<", style: .Plain, target: self, action: "segueBack")
navigationItem.leftBarButtonItem = newBackButton
That gives me a <, "ABC" would give me ABC etc but how do I trigger Swift to put up it's internal Back Button image. The code below doesn't work but I would have thought is along the right lines.
let backImg: UIImage = UIImage(named: "BACK_BUTTON_DEFAULT_ICON")!
navigationItem.leftBarButtonItem!.setBackgroundImage(backImg, forState: .Normal, barMetrics: .Default)
Has anyone worked out how to do this?
Try to add custom view as back button like as
var backButton = UIButton(frame: CGRectMake(0, 0, 70.0, 70.0))
var backImage = UIImage(named: "backBtn")
backButton.setImage(backImage, forState: UIControlState.Normal)
backButton.titleEdgeInsets = UIEdgeInsetsMake(10.0, 10.0, 10.0, 0.0)
backButton.setTitle("Back", forState: UIControlState.Normal)
backButton.addTarget(self, action: "buttonPressed", forControlEvents: UIControlEvents.TouchUpInside)
var backBarButton = UIBarButtonItem(customView: backButton)
var spacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
spacer.width = -15
self.navigationItem.leftBarButtonItems = [spacer,backBarButton]
It will look same as iOS back button
I struggled with this question for a while. Finally I got the back image with the following code:
let backImage = navigationController?.navigationBar.subviews[2].subviews[0].subviews[0].subviews[0] as! UIImageView).image
Before run the code above, make sure the back button is showing. Then you can save backImage to anywhere you want.
Here is the backImage I got.
Here is my solution:
override func viewDidLoad() {
...
let buttonBack = UIBarButtonItem(image: UIImage(named: "backButton"), style: .plain, target: self, action: #selector(buttonSavePressed(_:)))
self.navigationItem.leftBarButtonItem = buttonBack
let backButton = UIButton(frame: CGRect(x: 0, y: 0, width: 24.0, height: 24.0))
let backImage = UIImage(named: "backButton")
backButton.setImage(backImage, for: .normal)
backButton.setTitle("Back", for:.normal)
if #available(iOS 13.0, *) {
backButton.setTitleColor(.link, for: .normal)
} else {
backButton.setTitleColor(.blue, for: .normal)
}
backButton.addTarget(self, action:#selector(buttonSavePressed(_:)), for: .touchUpInside)
let backBarButton = UIBarButtonItem(customView: backButton)
let spacer = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spacer.width = -15
self.navigationItem.leftBarButtonItems = [spacer,backBarButton]
}
#objc func buttonBackPressed(_ sender: Any) {
...
}
If you want to get the default back button image, the arrow is a class of type _UINavigationBarBackIndicatorView.
Here follows the hack,
UIImage *imgViewBack ;
for (UIView *view in self.navigationController.navigationBar.subviews) {
// The arrow is a class of type _UINavigationBarBackIndicatorView. This is not any of the private methods, so I think
// this is fine for the AppStore...
if ([NSStringFromClass([view class]) isEqualToString:#"_UINavigationBarBackIndicatorView"]) {
// Set the image from the Default BackBtn Imageview
UIImageView *imgView = (UIImageView *) view;
if(imgView){
imgViewBack = imgView.image ;
}
}
}
Try this to replace the back button image:
let back_image = UIImage(named: "btn_back")
self.navigationBar.backIndicatorImage = back_image
self.navigationBar.backIndicatorTransitionMaskImage = back_image
If you don't like to have the "Back" title you can add this too:
self.navigationBar.topItem?.title = ""