Reloading a UINavigationItem - ios

I want to load my view controller with one navItem.rightBarButtonItem and change it to another based on a set of circumstances. It seems as if I can only load it once, on viewDidLoad. Is there a method for updating a bar button item after you've changed the icon?
func viewDidLoad() {
var iconOne = UIImage(named: "button")
let buttonOne = UIBarButtonItem(image: iconOne, style: UIBarButtonItemStyle.Plain, target: self, action: "funcOne")
self.navItem.rightBarButtonItem = buttonOne
//perform async query, if a condition holds true then:
var iconTwo = UIImage(named: "buttonTwo")
let buttonTwo = UIBarButtonItem(image: iconTwo, style: UIBarButtonItemStyle.Plain, target: self, action: "funcTwo")
self.navItem.rightBarButtonItem = buttonTwo
}
Full code:
override func viewDidLoad() {
super.viewDidLoad()
// Sets custom nav bar view so we can add multiple bar buttons
navBar = UINavigationBar(frame: CGRectMake(0, 20, UIScreen.mainScreen().bounds.size.width, 44))
navBar.barTintColor = UIColor.blackColor() // Sets bar to black
navBar.translucent = false
self.view.addSubview(navBar)
navItem = UINavigationItem(title: "\(name)") // Sets title
navBar.titleTextAttributes = [ NSFontAttributeName: UIFont(name: "Helvetica Neue", size: 25)!, NSForegroundColorAttributeName: UIColor.whiteColor()]
// Set icons
var backIcon = UIImage(named: "backButton")
let backButton = UIBarButtonItem(image: backIcon, style: UIBarButtonItemStyle.Plain, target: self, action: "backButton")
navItem.leftBarButtonItem = backButton
var userQuery = PFQuery(className: "Followers")
userQuery.whereKey("following", equalTo: username)
userQuery.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
if let follower = object["follower"] as? String {
if follower == PFUser.currentUser()!.username! {
var followingIcon = UIImage(named: "followingButton")
let followingButton = UIBarButtonItem(image: followingIcon, style: UIBarButtonItemStyle.Plain, target: self, action: "unfollowUser")
self.navItem.rightBarButtonItem = followingButton
self.navItem.rightBarButtonItem?.tintColor = UIColor.orangeColor()
} else {
var followIcon = UIImage(named: "followButton")
let followButton = UIBarButtonItem(image: followIcon, style: UIBarButtonItemStyle.Plain, target: self, action: "followUser")
self.navItem.rightBarButtonItem = followButton
self.navItem.rightBarButtonItem?.tintColor = UIColor.darkGrayColor()
}
}
}
}
} else {
println(error)
}
})

I'm not sure if this is possible. So, I made my own custom view where each bar button item would be. I set my right bar button item at var rightButton = UIButton(frame: CGRectMake(UIScreen.mainScreen().bounds.width - 50, 25, 30, 30)), added an action, and added the subview to the view.

Related

Keyboard (numpad) toolbar working but not showing

I tried to add a toolbar for my UITextFiled, the keyboard is set to numpad. It is working but the button is not showing. I created an extension for my UITextfield
extension UITextField {
/// Adding a done button on the keyboard
func addDoneButtonOnKeyboard() {
let doneToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
doneToolbar.barStyle = .default
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
let items = [flexSpace, done]
doneToolbar.items = items
doneToolbar.sizeToFit()
self.inputAccessoryView = doneToolbar
}
/// Done button callback
#objc func doneButtonAction() {
self.resignFirstResponder()
}
}
and then I am calling this extension like this
private lazy var fromInputField: CoinpassInput = {
let input = CoinpassInput()
input.keyboardType = .decimalPad
input.addTarget(self, action: #selector(fromInputFieldDidChange), for: .editingChanged)
input.addDoneButtonOnKeyboard()
return input
}()
the toolbar is showing and working but the 'done; button is not showing. If I click on the right corner of the toolbar. the keyboard will hide. I dont know what I am missing why the button is not showing.
Try this code, with slight modifications:
func addDoneButtonOnKeyboard() {
let doneToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
doneToolbar.barStyle = .default
doneToolbar.barTintColor = .red
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
done.tintColor = .yellow
doneToolbar.setItems([flexSpace,done], animated: false)
doneToolbar.isUserInteractionEnabled = true
self.inputAccessoryView = doneToolbar
}

Navigation controller delays before pushing to View Controller

I have a View Controller A with a collection view with list of items. I have to push to another View controller B.
When I select an item in Collection View I want this push to occur. But the push happens after a slight delay which I want to avoid.
I have had few lines of code after didSelect Item method and also NavigationController's navigation Bar setup and CollectionView setup in the View Did load and View Will Appear methods of the View Controller B.
I tried removing the codes after CollectionView Did Select just to check if this was causing the delay but the animation is still slow.
View Controller A Code.
DispatchQueue.global(qos: .background).async {
DispatchQueue.main.async {
//write your code here
var dict = projectsArray[indexPath.row - 1] as! [String:Any]
guard let id = dict["_id"] as? NSNumber else{return }
var canvasIds = NSArray()
if let idsAll = projectCanvasIds.object(forKey: id.stringValue) as? NSArray{
canvasIds = idsAll
}
dict["CanvasIds"] = canvasIds
let dict2 = dict as NSDictionary
IndexContentsModel.projectSlectedCanvasIds = dict2.mutableCopy() as! NSMutableDictionary
let vc = IndexCanvasViewController(nibName: "IndexCanvasViewController", bundle: nil)
self.navigationController?.pushViewController(vc, animated: true)
}
}
View Controller B Code
View Did Load has CollectionViewInit() and SetUI()
func collectionViewinit(){
let nib = UINib(nibName: "TopCanvasesCollectionViewCell", bundle: nil)
self.collectionView.register(nib, forCellWithReuseIdentifier: "topCanvasCell")
collectionView.register(UINib(nibName: "CanvasViewCollectionReusableView3", bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "canvasHeaderView")
}
func setUI(){
self.navigationController?.navigationItem.hidesBackButton = true
self.navigationController?.navigationBar.clipsToBounds = true
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
let hostStr = host
let userinfo = UserInfo.shared()
if let photo = userinfo?.dicJSON.object(forKey: "photo") as? String{
let profile = host + photo
imgView.sd_setImage(with: URL(string: profile), completed: nil)
}else{
imgView.image = UIImage(named: "test_Profile")
}
let button = UIButton()
button.addTarget(self, action:#selector(profileViewButtonPressed(_:)), for: UIControlEvents.touchUpInside)
button.frame = CGRect(x: 0, y: 0, width: 36, height: 36)// CGRectMake(0, 0, 36, 36)
button.layer.cornerRadius = button.frame.width / 2
button.layer.masksToBounds = true
button.setImage(imgView.image, for: UIControlState.normal)
// let profileButton = UIBarButtonItem(customView: button)
let searchImage = UIImage(named: "Search_Icon3")!
let notificationImage = UIImage(named: "Notification_Icon3")!
let profileImage = UIImage(named: "test_Profile")!
let backImage = UIImage(named: "Back_Icon3")!
let searchButton = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(searchViewButtonPressed(_:)))
let notificationButton = UIBarButtonItem(image: notificationImage, style: .plain, target: self, action: #selector(notificationViewButtonPressed(_:)))
let profileButton = UIBarButtonItem(image: profileImage, style: .plain, target: self, action: #selector(profileViewButtonPressed(_:)))
let backButton = UIBarButtonItem(image: backImage, style: .plain, target: self, action: #selector(backButtonPressed(_:)))
self.navigationItem.rightBarButtonItems = [profileButton,notificationButton,searchButton]
self.navigationController?.navigationBar.tintColor = UIColor(hexString: "#373839")
self.navigationItem.leftBarButtonItem = backButton
self.setValues()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = false
self.navigationController?.navigationItem.largeTitleDisplayMode = .never
self.navigationController!.navigationBar.backgroundColor = UIColor.white
} else {
// Fallback on earlier versions
}
if (self.isBeingPresented || self.isMovingToParentViewController) {
self.collectionView.animateViews(animations: animationsCanvas, reversed: false, initialAlpha: 0, finalAlpha: 1, delay: 0, duration: 0.07, animationInterval: 0.1, completion: nil)
}
}

Navigation Bar stays while Pushing and Poping the View Controllers creating a weird White color Effect while transition

I have a navigationController which is being used to move between my ViewControllers.
I have it setup normally and I am using Xib's for each View Controller.
extension UINavigationController{
func setup(){
if #available(iOS 11.0, *) {
self.navigationController?.navigationBar.prefersLargeTitles = true
self.navigationController?.navigationItem.largeTitleDisplayMode = .always
} else {
// Fallback on earlier versions
}
self.navigationBar.isTranslucent = true
self.view.backgroundColor = UIColor.red
self.navigationBar.clipsToBounds = true
self.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationBar.shadowImage = UIImage()
self.navigationBar.tintColor = UIColor(hexString: "#373839")
}
}
This is the extension I am using for my UINavigation Controller.
And in the pushed View (Second View), I need to have different Left and right buttons so I am hiding the navigation backbitten and having a custom code to setup my buttons.
func setUI(){
self.navigationController?.navigationItem.hidesBackButton = true
self.navigationController?.navigationBar.clipsToBounds = true
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 40, height: 40))
let hostStr = host
print(hostStr)
let searchImage = UIImage(named: "Search_Icon3")!
let notificationImage = UIImage(named: "Notification_Icon3")!
let profileImage = UIImage(named: "test_Profile")!
let backImage = UIImage(named: "Back_Icon3")!
let searchButton = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(searchViewButtonPressed(_:)))
let notificationButton = UIBarButtonItem(image: notificationImage, style: .plain, target: self, action: #selector(notificationViewButtonPressed(_:)))
let profileButton = UIBarButtonItem(image: profileImage, style: .plain, target: self, action: #selector(profileViewButtonPressed(_:)))
let backButton = UIBarButtonItem(image: backImage, style: .plain, target: self, action: #selector(backButtonPressed(_:)))
self.navigationItem.rightBarButtonItems = [profileButton,notificationButton,searchButton]
self.navigationController?.navigationBar.tintColor = UIColor(hexString: "#373839")
self.navigationItem.leftBarButtonItem = backButton
self.setValues()
}
But when I push from ViewController 1 to 2 and Pop from 2 to 1 I get this weird Nav bar present effect between transition

How to add multiple UIBarButtonItems on right side of Navigation Bar?

I would like to have more than a single UIBarButtonItem on the right side of my UINavigationBar. How can I achieve this?
An example of what I am trying are shown below - you can notice that the top right has more than one button.
Use this in swift:
override func viewDidLoad() {
super.viewDidLoad()
let editImage = UIImage(named: "plus")!
let searchImage = UIImage(named: "search")!
let editButton = UIBarButtonItem(image: editImage, style: .Plain, target: self, action: "didTapEditButton:")
let searchButton = UIBarButtonItem(image: searchImage, style: .Plain, target: self, action: "didTapSearchButton:")
navigationItem.rightBarButtonItems = [editButton, searchButton]
}
Write the action functions like this:
func didTapEditButton(sender: AnyObject){
...
}
func didTapSearchButton(sender: AnyObject){
...
}
Swift 4 & 5
override func viewDidLoad() {
super.viewDidLoad()
let editImage = UIImage(named: "edit")!
let searchImage = UIImage(named: "search")!
let editButton = UIBarButtonItem(image: editImage, style: .plain, target: self, action: #selector(didTapEditButton(sender:)))
let searchButton = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(didTapSearchButton(sender:)))
navigationItem.rightBarButtonItems = [editButton, searchButton]
}
#objc func didTapEditButton(sender: AnyObject){
}
#objc func didTapSearchButton(sender: AnyObject){
}
-(void)viewDidLoad{
UIBarButtonItem *anotherButton1 = [[UIBarButtonItem alloc] initWithTitle:#"Button_1" style:UIBarButtonItemStylePlain target:self action:#selector(button_1:)];
UIBarButtonItem *anotherButton2 = [[UIBarButtonItem alloc] initWithTitle:#"Button_" style:UIBarButtonItemStylePlain target:self action:#selector(button_2:)];
self.navigationItem.rightBarButtonItems=#[anotherButton1,anotherButton2];
}
In Swift 3 you can use:
let editImage = UIImage(named: "plus")!
let searchImage = UIImage(named: "search")!
let editButton = UIBarButtonItem(image: editImage, style: .plain, target: self, action: #selector(didTapEditButton))
let searchButton = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(didTapSearchButton))
navigationItem.rightBarButtonItems = [editButton, searchButton]
I think nothing of the above is going to work
Try this
var burgerItem = UIBarButtonItem(image: UIImage(named:"categories"), style: .Plain, target: self, action: "categories")
var weatherItem = UIBarButtonItem(title: "Weather", style: .Plain, target: self, action: "weather")
burgerItem.tintColor = UIColor.whiteColor()
weatherItem.tintColor = UIColor.whiteColor()
navigationItem.setRightBarButtonItems([burgerItem,weatherItem], animated: true)
You have to use navigationItem.setRightBarButtonItems and be carefull. navigationItem has to be of a view controller.
class testViewController:UIViewController {
ovverride func viewDidLoad() {
self.navigationItem.setRightBarButtonItems(...
}
}
Simply add this code:
self.navigationItem.leftBarButtonItem = nil
let button = UIButton(type: .custom)
button.setImage(UIImage (named: "ChatTab"), for: .normal)
button.frame = CGRect(x: 0.0, y: 0.0, width: 35.0, height: 35.0)
//button.addTarget(target, action: nil, for: .touchUpInside)
let barButtonItem = UIBarButtonItem(customView: button)
let button2 = UIButton(type: .custom)
button2.setImage(UIImage (named: "ActivityTab"), for: .normal)
button2.frame = CGRect(x: 0.0, y: 0.0, width: 35.0, height: 35.0)
//button.addTarget(target, action: nil, for: .touchUpInside)
let barButtonItem2 = UIBarButtonItem(customView: button2)
self.navigationItem.rightBarButtonItems = [barButtonItem, barButtonItem2]
This is the result:
With Swift 4
let editImage = UIImage(named: "toolbar_edit")!
let favoriteImage = UIImage(named: "toolbar_fav_solid")!
let editButton = UIBarButtonItem(image: editImage, style: .plain, target: self, action: #selector(didTapEditButton))
let favoriteButton = UIBarButtonItem(image: favoriteImage, style: .plain, target: self, action: #selector(didTapFavoriteButton))
navigationItem.rightBarButtonItems = [editButton, favoriteButton]
Click action for those buttons
#objc func didTapEditButton(sender: AnyObject) {
print("edit")
}
#objc func didTapFavoriteButton(sender: AnyObject) {
print("favorite")
}
Output screenshot (iPhone X)
Accepted answer as well as few of the answer is absolutely correct but in my case none of them work.
Reason : My View Controller was Inherited from UIViewController and I had to set Add to Cart Button and Search Button On Right hand side. And All my view controllers were a part of UITabbarController.
let editImage = UIImage(named: "OrdersTabIcon")
let searchImage = UIImage(named: "OrdersTabIcon")
let editButton = UIBarButtonItem(image: editImage, style: .plain, target: self, action: #selector(iconTapped))
let searchButton = UIBarButtonItem(image: searchImage, style: .plain, target: self, action: #selector(iconTapped))
Instead of using
self.navigationItem.setRightBarButtonItems([editButton, searchButton], animated: true)
Use This .
self.navigationController?.navigationBar.topItem?.setRightBarButtonItems([editButton, searchButton], animated: true)
This is may be help for you in objective-c,
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.navigationItem.title = #"Title";
UIBarButtonItem *logOutButton = [[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonItemStylePlain target:self action:#selector(ButtonClickedAtIndex1:)];
[logOutButton setTintColor:[UIColor blackColor]];
logOutButton.tag = 1;
UIBarButtonItem *syncBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Sync" style:UIBarButtonItemStylePlain target:self action:#selector(ButtonClickedAtIndex1:)];
[syncBarButtonItem setTintColor:[UIColor blackColor]];
syncBarButtonItem.tag = 2;
self.navigationItem.leftBarButtonItem = logOutButton;
self.navigationItem.rightBarButtonItem = syncBarButtonItem;
float systemVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (systemVersion >= 7.0) {
self.edgesForExtendedLayout = UIRectEdgeNone;
self.navigationController.navigationBar.translucent = NO;
}
}
return self;
}
Use navigationItem's rightBarButtonItems, which takes an array of UIBarButton. Appledoc
let share = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareTapped))
let add = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTapped))
navigationItem.rightBarButtonItems = [add, share]
I don't know wether an Interface Builder solution was not possible before, but at least with the most recent update (Xcode 11.0), it is possible to drag two UI Bar Buttons into the rightBarButton space. Two outlets and actions can then be dragged into the code like always.
Since the OP didn't ask for a solution without IB, I think this also qualifies as an answer.
For Xamarin iOS with the new updates, it is like:
UIBarButtonItem Button1 = new UIBarButtonItem(UIImage.FromBundle("Image1"), UIBarButtonItemStyle.Plain,YourEventHandler);
UIBarButtonItem Button2 = new UIBarButtonItem(UIImage.FromBundle("Image1"), UIBarButtonItemStyle.Plain,YourEventHandler);
NavigationItem.SetRightBarButtonItems(new[]{ Button1, Button2 }, true);

Swift IOS - Using UIPickerView AND Keyboard

In my app when user clicks on UITextField he should be able to pick up a value from UIPickerView OR enter his own value using keyboard.
What's the best way of doing it in terms of user experience and ease of implementation?
UIPickerView with toolbar is already implemented.
I'd appreciate both advice on best way of doing it and example code of switching keyboard <-> pickerview.
I've tried adding a button "Show keyboard" on pickerview's toolbar and adding the following code:
func showKeyboard() {
selectedTextField.inputView = nil
}
But clicking this button doesn't do anything. Also I'm not sure it's a good way in terms of UX.
Here's the solution:
var useKeyboard:Bool = true
func showKeyboard() {
if useKeyboard {
useKeyboard = false
selectedTextField.inputView = nil
selectedTextField.reloadInputViews()
selectedTextField.keyboardAppearance = UIKeyboardAppearance.Default
selectedTextField.keyboardType = UIKeyboardType.Default
} else {
useKeyboard = true
selectedTextField.inputView = nil
selectedTextField.reloadInputViews()
createPicker(selectedTextField)
selectedTextField.resignFirstResponder()
selectedTextField.becomeFirstResponder()
}
}
// That's my custom picker - adjust whatever you need
func createPicker(sender: UITextField){
selectedTextField = sender
// Create picker view
var newPickerView: UIPickerView
newPickerView = UIPickerView(frame: CGRectMake(0, 200, view.frame.width, 300))
newPickerView.backgroundColor = .whiteColor()
// Only for UIPickerView
newPickerView.showsSelectionIndicator = true
newPickerView.delegate = self
newPickerView.dataSource = self
// Create toolbar
var toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.Default
toolBar.translucent = true
toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
toolBar.sizeToFit()
// Create buttons
var doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Plain, target: self, action: "donePicker")
var spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
var cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "cancelPicker")
var customButton = UIBarButtonItem(title: "Keyboard", style: UIBarButtonItemStyle.Plain, target: self, action: "showKeyboard")
// Assign buttons to toolbar
toolBar.setItems([cancelButton, spaceButton, customButton, doneButton], animated: false)
toolBar.userInteractionEnabled = true
// Add pickerview and toolbar to textfield
sender.inputView = newPickerView
sender.inputAccessoryView = toolBar
}
func donePicker() {
useKeyboard = true
selectedTextField.resignFirstResponder()
}
func cancelPicker() {
useKeyboard = true
selectedTextField.resignFirstResponder()
}

Resources