What is the right approach to achieve what you see in the gif? It's a tableview with textfields. When you tap a textfield, a textview shows up with it's keypad. I have a tableview with a custom tableviewcell with a textfield(valueTextField). And in cellforrow i set the inputview of the textfield to a UITextView. When i press the textfield, the textview is supposed to show the toolbar on top (with a "Done" button) but no toolbar shows. When i tap the textview, still no toolbar.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! EditProfileTableViewCell
cell.isUserInteractionEnabled = true
cell.valueTextField.isUserInteractionEnabled = true
cell.valueTextField.delegate = self
toolBar = UIToolbar()
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(editorDone))
toolBar.setItems([doneButton], animated: false)
editorTextView = UITextView(frame: CGRect(x:0, y:0, width:view.bounds.width, height:view.bounds.height))
cell.valueTextField.inputAccessoryView = toolBar
cell.valueTextField.inputView = editorTextView
return cell
}
The example you show is simply using a UINavigationController to navigate to a separate UIViewController when the cell is tapped. In this view controller, the UITextField will be handled something like this.
// View controller subclass conforming to UITextFieldDelegate protocol
class MyDetailViewController: UIViewController, UITextFieldDelegate {
// Set an IB Outlet to the text field in storyboard
#IBOutlet myTextField: UITextField!
override viewDidLoad() {
myTextField.delegate = self
// ToolBar
let toolBar = UIToolbar()
// Optional styling
toolBar.barStyle = .default
toolBar.isTranslucent = true
toolBar.tintColor = .black
toolBar.layer.borderWidth = 0
toolBar.sizeToFit()
// Buttons
let buttonOne = BarButtonItem(title: "One", style: .plain, target: self, action: #selector(yourSelectorOne(_:)))
let buttonTwo = BarButtonItem(title: "One", style: .plain, target: self, action: #selector(yourSelectorTwo(_:)))
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolBar.setItems([buttonOne, spacer, buttonTwo], animated: false)
toolBar.isUserInteractionEnabled = true
textField.inputAccessoryView = toolBar
}
}
This will create two buttons, one on the left and one on the right of the toolbar. The type of keyboard can be set in Interface Builder.
To get this by tapping on the text field in the cell directly, without navigating to a new view controller, you could set your custom UITableViewCell subclass as the text field delegate.
Note that you will need to provide method stubs to conform to the UITextFieldDelegate protocol. These are not essential for this example so I have omitted them. XCode will offer to populate them for you.
There are few things in your code you want to change.
1) This view's frame causes that strange behavior:
UITextView(frame: CGRect(x:0, y:0, width:view.bounds.width, height:view.bounds.height))
2) The reason why you make this mistake is because you are confusing
.inputAccessoryView
.inputView
3) The gif you posted is based on navigationBar buttons. Basically, it by tapping on the cell it presents a detailedViewController with two items set in navigationBar
Related
UIButton gestures doesn't recognize in child view controller.
UIButton add targer work (button get target action)
User interaction is turned on everywhere, button size is okay. I try to set childVC as main, and then all work good, debug view hierarchy said that button view over other elements. IDK where is problem. I can provide more code, just tell me.
Add target code:
view.buttonOfLanguageFromTranslate.addTarget(self, action: #selector(self.openDetailView(_:)), for: .touchDown)
Add child VC code:
let childVC = ChildVC()
view.addSubview(childVC.view)
self.addChild(childVC)
childVC.didMove(toParent: self)
childVC.view.translatesAutoresizingMaskIntoConstraints = false
self.view.isUserInteractionEnabled = true
self.childVC = childVC
Button initialization:
var button: UIButton = {
let button = UIButton()
button.setTitle("Title", for: .normal)
button.setTitleColor(.black, for: .normal)
button.setTitleColor(.green, for: .selected)
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
The problem was with
childVC.translatesAutoresizingMaskIntoConstraints = false
(in mainVC)
When i remove it, childVC recognise my tap
and i dont set additional size for childVC, view of childVC is display correct but not childVC. (as i think)
I made a navigation bar with three buttons - Plans,Visit and Documents and every time a button is selected/clicked a view is added as a child into a container view (Code for the other buttons are similar)
#IBAction func planAction(_ sender: UIButton) {
let newPlan = sender.frame.origin.x
scrollView.subviews.forEach{$0.removeFromSuperview()}
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextController = storyBoard.instantiateViewController(withIdentifier: "PlansViewController2") as! PlansViewController2
addChildView(viewController: nextController, in: scrollView)
self.movingView.frame.origin.x = newPlan
}
Now I want to add a tool bar item that only shows up when Plans or Documents is selected and disappears when Visit is selected.
At the moment I add my tool bar item in the viewDidLoad method:
self.toolbarItems = [UIBarButtonItem(title: "Kategorienliste", style: .plain, target: self, action: #selector(handleCategoryListTap(sender:)))]
How can I add a toolbarItem when a certain button is selected and remove it when another button is selected? Thanks in advance!
You can create your UIBarButtonItem with a custom view like:
let button = UIButton()
let barButtonItem = UIBarButtonItem(customView: button)
self.toolbarItems = [barButtonItem]
to hide / show you can access the button as the following:
let barButtonItem = self.toolbarItems.first
barButtonItem.customView?.isHidden = true
Hope it helps.
I want to change the title of backbutton to any name in swift 3.I tried many ways but none of them worked for me.
self.navigationItem.backBarButtonItem?.title="Title"
self.navigationController?.navigationItem.backBarButtonItem?.title="Title"
Just for information i have written below code in appdelegate.
let backImage : UIImage = UIImage(named:"backArrow")!
UINavigationBar.appearance().barTintColor = UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0)
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName : UIColor.white]
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, 0), for: .default)
IQKeyboardManager.sharedManager().enable = true
self.window?.backgroundColor = UIColor.white
Navigation item back button name will be same as the title of previous view controller which is pushing it to the navigation stack :)
So if VC A pushes VC B, back button in VC B will be A.
So all you can do is, to change the title of the previous viewController before pushing the new viewController using code :)
self.navigationItem.title = "ABCD"
And in ViewWillAppear of VC A,you can revert the title back to whatever it was earlier :)
self.navigationItem.title = "Back to xyz"
All that being said, if you don't want all this circus :) you can simply hide the default back button using,
self.navigationItem.hidesBackButton = true
in your VC B, create a UIBarButton item, set whatever the title you want to set and then set that as leftBarButtonItem :) using,
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("ABCD", comment: "ABCD"), style: .plain, target: self, action:#selector(self.abcdTapped:)
of course now that will not show "<" icon :) Now if you want that as well you can add it as a image to back bar button item :) but its cumbersome :)
Hope it helps :)
You will have to set the backBarButtonItem property of the navigationItem of the viewController that you push the said viewController from.
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.plain, target: nil, action: nil)
However, you must set this for each viewController.
This is the way:
extension UINavigationController {
func addCustomBackButton(title: String = "Back") {
let backButton = UIBarButtonItem()
backButton.title = title
navigationBar.topItem?.backBarButtonItem = backButton
}
}
In Swift 3.0 put below code in appdelegate didFinishLaunchingWithOptions method its worked perfectly for me
let backImage = UIImage(named: "BackNavigation")?.withRenderingMode(.alwaysOriginal)
UINavigationBar.appearance().backIndicatorImage = backImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backImage
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -80.0), for: .default)
The last line will remove the title of Navigation Back Button if you don't want to remove title then just comment it
I didn't find the answer that I was looking for so I share with you my solution.
Sometimes you have to change the text of the back button in the parent ViewController and not in the ViewController where seems to be defined the back button, remember that a navigation controller stacks ViewControllers one after another.
In my case I did this on the function prepare(for segue: ) of the "ParentViewController":
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showChildViewController" {
if let childViewController = segue.destination as? ChildViewController {
let backItem = UIBarButtonItem()
backItem.title = "Back"
navigationItem.backBarButtonItem = backItem
}
}
Try following steps to set image to your back button..
Output:
Step 1:
Add following code to your AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
var backButtonImage = UIImage(named: "Your Image Name")
backButtonImage = backButtonImage?.stretchableImage(withLeftCapWidth: 0, topCapHeight: 0)
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, for: .normal, barMetrics: .default)
UINavigationBar.appearance().barTintColor = UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0)
UINavigationBar.appearance().tintColor = UIColor.white
return true
}
Step 2:
Add following code to your MainVC
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Title 1"
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white, NSFontAttributeName:UIFont(name:"HelveticaNeue", size: 20)!]
}
Step 3:
Add following code to your DestVC or 2ndVC
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "Title 2"
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.white, NSFontAttributeName:UIFont(name:"HelveticaNeue", size: 20)!]
}
Step 4:
Select your navigationBar from your StoryBoard and goto Attribute Inspector. Under Navigation Item change your Back Button name enter a empty space or programatically create a back button with plain title..
Step 5:
Add icon image to your Assets. 1x29pt,2x58pt and 3x87pt. I am not sure about the asset image size.Check with apple doc about the size class..
Update:
My Similar answer related to this post.
How to customize the navigation back symbol and navigation back text?
You can easily do that from the storyboard by setting the title of the previous screen. Image explaining how to do that from storyboard - or you can do that by adding the following code to the view controller you're navigating BACK to.
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
let backItem = UIBarButtonItem()
backItem.title = "Title"
navigationItem.backBarButtonItem = backItem
}
in viewDidLoad()
let backBarButtonItem = UIBarButtonItem(title: "You back button title here", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backBarButtonItem
I'm not sure why this piece of code which is supposed to embed two bar button items in a navigation controller's toolbar won't work. The toolbar itself is visible when I run my code, but not the bar button items. What am I doing wrong here? Thanks for attention.
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
//Tool bar appearance
toolbar.barTintColor = UIColor.blackColor()
//Show tool bar by default
self.navigationController?.toolbarHidden = false
//Icons all located in images.xcassets
let homeImage = UIImage(named: "home")
let gameImage = UIImage(named: "logo")
var toolBarItems = [UIBarButtonItem]()
let homeButton = UIBarButtonItem(image: homeImage, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(NavigationController.toHome))
homeButton.title = "Home"
let gameButton = UIBarButtonItem(image: gameImage, style: UIBarButtonItemStyle.Plain, target: self, action: #selector(NavigationController.toGame))
homeButton.title = "Game"
//Place the bar items in toolBarItems array
toolBarItems.append(homeButton)
toolBarItems.append(gameButton)
//self.toolbar.items = toolBarItems
self.toolbar.setItems(toolBarItems, animated: true)
}//End viewDidLoad
func toHome() {
let homeVC = HomeViewController(nibName: "HomeViewController", bundle: nil)
self.pushViewController(homeVC, animated: true)
}
func toGame() {
let gameVC = GameViewController(nibName: "GameViewController", bundle: nil)
self.pushViewController(gameVC, animated: true)
}
}
Did you create a second .swift file for your dependent controller? You should move this code to the dependant controller file
self.navigationController?.toolbarHidden = false
let button1 = UIBarButtonItem(title: "home", style: .Plain, target: self, action: #selector(SecondViewController.home))
let myToolBar = [button1]
self.setToolbarItems(myToolBar, animated: true)
I am not sure but I think your buttons has size 0. So maybe you should add some constraints or view frame size. You can try debugging using the view hierarchy debugger.
Maybe you just have to replace this self.navigationController?.toolbarHidden = false
With this toolbarHidden = false
I'm confused by your code. Is the class you show us, the one Navigation Controller where all other ViewController depend on or is it itself one dependent ViewController that in this case appears to be a Navigation Controller? Or is it a Navigation Controller by mistake? (not very likely)
Why I ask? At one time you're referring to the parent navigation controller with self.navigationController?.toolbarHidden = false which is not this navigation controller itself. Then in the rest of the code, you refer to this controller itself.
Hope this leads to the right thinking.
I have two view A and view B.
From view A to view B, I do not use navigation controller, I used performSegueWithIdentifier() and I don't want to use navigation controller to pass view A to view B.
But in the view B, I want to add a leftBarButtonItem in the navigation bar(I have embed a navigation controller for view B) like a back button with a arrow.
In order to achieve 100% same with the system backbitten with arrow. I use NSMutableAttributedString and UIButton. code is below:
let string = "< Retour" as NSString
var attributedString = NSMutableAttributedString(string: string as String)
let ArrowAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor(), NSFontAttributeName: UIFont.systemFontOfSize(20)]
let TextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor(), NSFontAttributeName: UIFont.systemFontOfSize(10)]
attributedString.addAttributes(ArrowAttributes, range: string.rangeOfString("<"))
attributedString.addAttributes(ArrowAttributes, range: string.rangeOfString(" Retour"))
let backbutton = UIButton(type: .Custom)
backbutton.addTarget(self, action: "back:", forControlEvents: .TouchUpInside)
backbutton.setAttributedTitle(attributedString, forState: UIControlState.Normal)
self.navigationItem.setLeftBarButtonItem(UIBarButtonItem(customView: backbutton), animated: true)
rightBtn = UIBarButtonItem(title: "Ok", style: .Plain, target: self, action: "save:")
But I can not see left button in the navigation bar in view B…why I can not see it in the navigation bar? Why the left button disappear?
Thank you very much.
I have tried the new code for a label, but it doesn't work yet...
let barButtonBackStr = "< Back"
let attributedBarButtonBackStr = NSMutableAttributedString(string: barButtonBackStr as String)
attributedBarButtonBackStr.addAttribute(NSFontAttributeName,
value: UIFont(
name: "AmericanTypewriter-Bold",
size: 18.0)!,
range: NSRange(
location:0,
length:1))
let label = UILabel()
label.attributedText = attributedBarButtonBackStr
label.sizeToFit()
let newBackButton = UIBarButtonItem(customView: label)
self.navigationController!.navigationItem.setLeftBarButtonItem(newBackButton, animated: true)
Thank you
Try a backbutton.sizeToFit() you'll see your button
You create a button but you never set the frame
You can also set the frame directly instead of sizeToFit() method like backbutton.frame = CGRectMake(0, 0, 100, 20)
PS: TextAttributes wasn't used
You must write it to :
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
...
}
Try to set a breakpoint after your UI design and try to launch the Debug View Hierarchy to see if your button exist or is hidden by another object
Next, after you have set your button try to make:
self.navigationController!.navigationItem.leftBarButtonItem.customView.sizeToFit()