My scenario, I am trying to implement keyboard with toolbar view using Swift. Here, I need to do whenever I click the button need to show keyboard with toolbar view view without using textview or textfield.
Below My code I am using
Simply I drag UIView to the top of the bar of current ViewController
I declared below code for IBOutlet
#IBOutlet private var toolbarView: UIView!
#IBOutlet private var textView: UITextView!
In ViewDidload I used below code
override func viewDidLoad() {
super.viewDidLoad()
textView.inputAccessoryView = toolbarView
}
In Button action now I am calling like below
#IBAction func CircleClick(_ sender: Any) {
self.textView.becomeFirstResponder()
}
You need to define an outlet for textfield for referencing it.
#IBOutlet weak var textfield:UITextField!
You can activate any text field by calling becomeFirstResponder() on the UITextfield object.
textfield.becomeFirstResponder()
You can call this function in the IBAction of any action of UIButton.
#IBAction func btnShowKeyboardClicked(){
textfield.becomeFirstResponder()
}
For maintaining the custom toolbar as the accessory view, you need to set it to the text field object. First either create the custom toolbar view from code or load using XIB, and assign it to the inputAccessoryView of textfield.
let customInputAccessoryView = CustomView() // Load from XIB or from Code
textfield.inputAccessoryView = customInputAccessoryView
I would like demonstrate it from scratch, so you can learn from this guide. First off all you should create a view, simply click Command+N button or choose File-New-File from the menu of Xcode. Choose a View template under User Interface section as shown below. Give it a name, in this case a Header (you can name it whatever you want).
And create a class to it, again click Command+N or from menu as I mentioned above. In this case choose a Cocoa Touch Class under Source section as shown below. And name it, as a HeaderView. Subclass of UIView
Open up your Header.xib file from the Project Manage. Click your view, give it a size as a freeform, Top bar to none, and Bottom bar to none. Add a UIButton to this view, I guess you know already, how to do it. And click this view, go to the Identity Inspector. And give it a class, in this a HeaderView.swift is our class.
Connect your button as shown below and we are done:
Now all of our focus in code, insert following line of code to the viewDidLoad().
override func viewDidLoad() {
super.viewDidLoad()
// Load the view using bundle.
// Make sure a nib name should be correct
// And cast it to the class, something like this
if let headerView = Bundle.main.loadNibNamed("Header", owner: self, options: nil)?.first as? HeaderView {
// Do some stuff, configuration of the view
headerView.frame = CGRect.init(x: 0, y: 0, width: self.view.frame.width, height: 44)
headerView.button.setTitle("Done", for: .normal)
headerView.button.addTarget(self, action: #selector(self.doneAction(sender:)), for: .touchUpInside)
// Add this view as an accessory to the text field or text view, in this case I have added this to the text field
self.textField.inputAccessoryView = headerView
}
}
Create a custom function to the done button:
#objc func doneAction(sender: UIButton) {
// Do something
// Resing your text field or text view
self.textField.resignFirstResponder()
}
Congrats! You're done. I hope it will help.
Related
The program is designed to have the screen toggle between black and white when the button is pressed. The problem is this is supposed to be accomplished with a button and not a switch. What is wrong with this code? When I run the program the background doesn't switch. Any suggestions on how to fix this issue?
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// set the background color to white when opened
backgroundView.backgroundColor = .white
}
#IBOutlet weak var OnOffButton: UIButton!
#IBOutlet var backgroundView: UIView!
#IBAction func OnOff(_ sender: AnyObject) {
// write your code here
// code should change background color to black if it is white and vice versa.
if backgroundView.backgroundColor == .white {
backgroundView.backgroundColor = .black
} else {
backgroundView.backgroundColor = .white
}
}
}
I just created a brand new single view iOS app and it works perfectly.
In the new project, I added a UIButton to a the first scene in the storyboard and wired it to OnOff:
Note: you should NOT start functions with a capital letter by the way. It should be onOff:. Use Refactor to change this.
Then I dragged a UIView to that scene, right clicked on view and added a New Referencing Outlet, dragged from the + to the right up to the View Controller text on the left and assigned it to backgroundView.
It ran perfectly on the first try. It's possible that you have miswired the IBOutlet or IBAction. Add a breakpoint inside of your OnOff: function and see if it is triggered when you click on the button. If it is, make sure that the IBOutlet for backgroundView is properly hooked up by entering the following in the console:
po self.backgroundView
If it is nil, then it's not hooked up properly to the UIView.
Good luck!
I have a UIButton that is within a nested scrollview (a vertically paged scrollview inside a horizontally paged scrollview). My problem is when I tap the button it highlights but it does not trigger a segue that I have it linked to. I then tried to link it to an IBAction function where I placed a breakpoint and when I tapped the button I did not hit that breakpoint, so my button is also not triggering IBActions either.
I've tried turning off delays content touches for both scrollviews and that didn't work. All that did was make the button highlight as soon as I tapped it rather than weighting a little bit before highlighting. Either way, my button highlights when I tap it but none of my outlets (segues or IBActions) are triggering which I thought was very strange. I've found other people online with similar issues but their buttons didn't even highlight. Mine highlights so I know its getting input from the user.
Here is how I am instantiating the nested scrollview. The main horizontal scrollview is created in my storyboard then in its ViewController viewDidLoad method I do this to nest the vertical scrollview. The vertical scrollview is what contains my button.
let readingVC = storyboard!.instantiateViewControllerWithIdentifier("ReadingViewController") as! ReadingRingViewController
readingVC.read = reading.minutesRead
readingVC.goal = reading.minutesGoal
readingVC.selectedDate = selectedDate
readingVC.today = today
let readingView = readingVC.view
let scrollPage2 = UIScrollView(frame: CGRectMake(readingView.bounds.size.width,0,readingView.bounds.size.width, readingView.bounds.size.height))
scrollPage2.addSubview(readingView)
scrollPage2.contentSize = CGSize(width: readingView.bounds.size.width, height: readingView.bounds.size.height*2)
scrollPage2.pagingEnabled = true;
scrollPage2.alwaysBounceVertical = true
scrollPage2.userInteractionEnabled = true
let readingBottomView = storyboard!.instantiateViewControllerWithIdentifier("ReadingBottomViewController").view
let scrollPage2Bottom = UIScrollView(frame: CGRectMake(0,readingView.bounds.size.height,readingBottomView.bounds.size.width, readingBottomView.bounds.size.height*2))
scrollPage2Bottom.addSubview(readingBottomView)
scrollPage2Bottom.contentSize = CGSize(width: readingBottomView.bounds.size.width, height: readingBottomView.bounds.size.height)
scrollPage2.addSubview(scrollPage2Bottom)
scrollPage2.sendSubviewToBack(scrollPage2Bottom)
Here is the code for the viewController that my button is in. I've linked it to the IBAction and also linked it to another viewController as a push segue
#IBAction func start(sender: AnyObject) {
var x = 0
var y = 0
x = y + x
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "StartReading" {
let destVC = segue.destinationViewController
}
}
I solved my own question. The reason the button's actions were not working was because I was adding the view the button was in as a subview but forgetting to also add the view controller for the button's view as a subviewcontroller. So I inserted the lines following lines of code after I instantiated readingVC and set its member variables:
self.addChildViewController(readingVC)
readingVC.didMoveToParentViewController(self)
Now the button works exactly as expected
Hello I am developing app which has UI like below images..
I am not able to understand how to create bottom swipe up view.
I have tried swipe up gesture on bottom view to open it.
But I want to open bottom view with finger (means slow upward drag of view should reveal bottom view slowly)
I am using auto layout and storyboard. How do I achieve this ?
I have searched a lot and I got this https://github.com/crocodella/PullableView but I am not able to add this view with storyboard and auto layout.
I Just want say before solution is that this is not gonna be drag like effect for that you need to use gesture...but It gives you similar effect if you strongly need it with button click.. I think its not what you want but this give you an option if you want
For drag bottom view to top,you shold use gesture and this may help you
Drag Down UIView in iOS 5
or this
http://www.jondev.net/articles/Dragging_View_with_Finger_(iPhone)
You got the similar effect using constant property of constraints..like Give the height constraint to bottom view and use constant property on click event to swipe up and down.
Still confused!!! Here is the solution
UI setup
Constraints Setup
After that You just need to make some outlets and click event of button...
make an outlet of height constraint of bottom view
make an outlet of button to change its title to up/down
make and click event of button
After this procedure you need to code on button action, So here is that code
class ViewController: UIViewController {
// Button outlet
#IBOutlet weak var btnUp: UIButton!
// Height Constraint outlet
#IBOutlet weak var constHeightBottomView: NSLayoutConstraint!
// Boolean property to handle click
var clicked = true
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func btnUpClicked(sender: UIButton) {
if clicked{
self.clicked = !clicked
UIView.animateWithDuration(0.2, animations: {
self.btnUp.setTitle("Down", forState: .Normal)
self.constHeightBottomView.constant = 200
self.view.layoutIfNeeded()
})
}
else{
self.clicked = true
UIView.animateWithDuration(0.2, animations: {
self.btnUp.setTitle("Up", forState: .Normal)
self.constHeightBottomView.constant = 0
self.view.layoutIfNeeded()
})
}
}
}
and the output of this work would be
I am trying to add a button ontop of a uitableview controller table view. The view controller has a navigation controller and static cells, which is why it is a uitableviewcontroller and not a uiviewcontroller. Now I am trying to add a button at the bottom of the screen that is attached to the navigation controller so that it doesn't scroll with the table view.
I am trying to make something similar to what is below. It has a navigation controller for the top bar, a table view with static cells and then a button, but how did they do the button?
Image: http://postimg.org/image/ilsmqqrip/
Thanks!
UPDATE: How can I use a uiviewcontroller with a tableview with static cells using Swift?
I find Container Views very useful in this scenario! A clean solution and very easy to implement.
Just create a normal UIViewController, add your button and a ContainerView as subviews of this UIViewController (the middle one in the image below). Finally create Embed Segue from ContainerView to your UITableViewController (the one on the right).
This way you can use static cell prototypes, not being limited only to UITableView at the same time.
Result:
there is a better solution for this. you can do this by disabling the Auto Layout(button.translatesAutoresizingMaskIntoConstraints = false) property of the corresponding Button or any UIView for floating button:
Swift 4
//create a button or any UIView and add to subview
let button=UIButton.init(type: .system)
button.setTitle("NEXT", for: .normal)
button.frame.size = CGSize(width: 100, height: 50)
self.view.addSubview(button)
//set constrains
button.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
button.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor, constant: -10).isActive = true
button.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor, constant: -10).isActive = true
} else {
button.rightAnchor.constraint(equalTo: tableView.layoutMarginsGuide.rightAnchor, constant: 0).isActive = true
button.bottomAnchor.constraint(equalTo: tableView.layoutMarginsGuide.bottomAnchor, constant: -10).isActive = true
}
I did something similar with UITableViewController and a static datasource. I added the button in the footerview of my tableview.
To make it align to the bottom of the screen i needed this code in my viewcontroller:
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Make footerview so it fill up size of the screen
// The button is aligned to bottom of the footerview
// using autolayout constraints
self.tableView.tableFooterView = nil
self.footerView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.tableView.frame.size.height - self.tableView.contentSize.height - self.footerView.frame.size.height)
self.tableView.tableFooterView = self.footerView
}
In short, I resize the footerview to take up all the remaining space after the contentsize of the table view is removed. Since the button is aligned to the bottom of the footerView with autolayout, it will stay in the bottom of the screen.
The Storyboard:
Here is the result:
The UITableViewController will take up the whole space, so you won't be able to add the button. Refactor your UITableViewController based code into UIViewController with UITableView manually added. This way you will be able to set the size of your table view and put the button to the bottom.
Unfortunately UITableViewController has a tableView as its top level view. Of course if you look in the view debugger you can see that the tableview is not the root view. Therefore you can add the buttons to the tableView's window programatically. If you have to do it after the fact, this is probably the easiest way to add a top level element over a UITableViewController. Otherwise if you are doing it in the initial design, you can use container view for your buttons and a UITableViewController for the TableView. The downside of this approach is you end up with two view controllers, one for the container and one for the table and its often necessary to pass information back and for between them. If you are using swift you can simplify this by nesting the tableViewcontroller inside the container view controller class.
If you want to add a button to the window, you can do this lazily once you are sure that the view has a window. Note that the buttons belong to the window and not to the view controller, so its your responsibility to remove them when the view controller disappears.
private weak var button: UIButton!
...
override func didMove(toParentViewController parent: UIViewController?) {
super.didMove(toParentViewController: parent)
guard self.button == nil, let window = tableView.window else {
return
}
let button = UIButton(frame: CGRect(x:0, y:40, width: 200, height: 20))
button.setTitle("This is a red button", for: .normal)
button.backgroundColor = UIColor.red
window.addSubview(button)
self.button = button
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
button?.removeFromSuperview()
}
Step 1 :-
Drag and drop one uiview to UITable View Controller (Static)
Automatically it sticks to the bottom.
If you need to, you can also add two buttons inside UIView... It depends on your requirements.
Step 2 :-
Connect the outlet for uiview (outletView)
Step 3 :-
Add this below code in View Will Appear.
override func viewWillAppear(_ animated: Bool) {
outletViewBottom.backgroundColor = .red
tableView.addSubview(outletViewBottom)
// set position
outletView.translatesAutoresizingMaskIntoConstraints = false
outletView.leftAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.leftAnchor).isActive = true
outletView.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor).isActive = true
outletView.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor).isActive = true
outletView.widthAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.widthAnchor).isActive = true
outletView.heightAnchor.constraint(equalToConstant: 50).isActive = true // specify the height of the view
}
Step 4 :-
Now run the code... Happy coding.
all you need to do is to add your Top view whichever it is to the navigationController.view like so:
self.navigationController?.view.addSubview(YOUR_TOP_VIEW)
so if you need a sticky button/view etc... on top of TableViewController which does not scroll with tableView, use this approach.
Here is a UIViewController, with a UITableView added as a subview. At the top right, you can see a dropdown that says Content: Dynamic Prototypes. Change it to Static Cells.
What I'm trying to do is to create something similar to the "find on page" search function in Safari on iPad.
I'm using a UIToolbar with some items in it and attached it to the keyboard by setting it as an inputAccessoryView on the UITextField. Works like a charm, but there is one thing I can't figure out. In Safari, when you search for something, the keyboard disappears but the tool bar remains on the bottom of the screen.
Does anyone have a clue on how to accomplish this? The only solution I can think of is to respond to a keyboard dismissed event and then pull out the UIToolBar and create a custom animation that moves it to the bottom of the screen. But this is hacky. I am looking for a more elegant solution. Something that can make me decide what to do with the input accessory view when the keyboard gets dismissed.
It's done like this:
Assign your UIToolbar to a property in your view controller:
#property (strong, nonatomic) UIToolbar *inputAccessoryToolbar;
In your top view controller, add these methods:
- (BOOL)canBecomeFirstResponder{
return YES;
}
- (UIView *)inputAccessoryView{
return self.inputAccessoryToolbar;
}
And then (optionally, as it usually shouldn't be necessary), whenever the keyboard gets hidden, just call:
[self becomeFirstResponder];
That way, your inputAccessoryToolbar will be both your view controller's and your text view's input accessory view.
I've ended up with UIToolBar that is not assigned as input accessory view, and slide up and down on UIKeyboardWillShowNotification / UIKeyboardWillHideNotification
Update to Swift 4, based on prior answers. If you add toolbar via storyboards you can do this
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet var toolbar: UIToolbar!
override var canBecomeFirstResponder: Bool {
get {
return true
}
}
override var inputAccessoryView: UIView {
get {
return self.toolbar
}
}
override func viewDidLoad() {
super.viewDidLoad()
textField.inputAccessoryView = toolbar
}
}
In this case, whenever text field resigns first responder, it defaults first responder to main view. Keep in mind, you might want to explicitly resign first responder, and set main view as first responder if there are multiple UI elements and first responder defaults to undesired view after resignation.
Adding to #arik's answer, here is the Swift version:
class ViewController: UIViewController {
#IBOutlet var textField: UITextField!
// Input Accessory View
private var inputAccessoryToolbar: UIToolBar?
override func canBecomeFirstResponder() -> Bool {
return true
}
override var inputAccessoryView: UIView? {
return inputAccessoryToolbar
}
override func viewDidLoad() {
super.viewDidLoad()
inputAccessoryToolbar = UIToolbar(frame: CGRectMake(0, 0, view.frame.size.width, 50))
textField.inputAccessoryView = inputAccessoryToolbar
}
// UITextFieldDelegate
func textFieldShouldReturn(textField: UITextField) -> Bool {
becomeFirstResponder()
return true
}
}
Thanks for the clean solution!
You may also need to work around the bug with the inputAccessoryView not respecting the safe area margins and thus not making room for home indicator thing on iPhone X: iPhone X how to handle View Controller inputAccessoryView?
I found the easiest solution when you have a UIToolbar from a xib and you are also using that UIToolbar as the inputAccessoryView of a text field is to embed the toolbar in a UIView when you return it from your overridden inputAccessoryView, and make the containing UIView taller by the safeAreaInsets.bottom. (Other solutions suggest constraining the bottom of the toolbar to the safe area in a subclass, but this leads to constraint conflicts and also means the area under the toolbar is the wrong colour.) However, you have to also bear in mind that the text field can have focus even when there is no keyboard on the screen (for instance if there is an external keyboard), so you need to change the inputAccessoryView of the text view to this toolbar-within-a-UIView in that case as well. In fact it will probably make things simpler to just always use the containing view and adjust the size of it appropriately. Anyway, here's my override of inputAccessoryView:
override var inputAccessoryView: UIView? {
if toolbarContainerView == nil {
let frame=CGRect(x: toolBar.frame.minX, y: toolBar.frame.minY, width: toolbar.frame.width, height: toolBar.frame.height+view.safeAreaInsets.bottom)
toolbarContainerView = UIView(frame: frame)
}
if (toolbar.superview != toolbarContainerView) {
//this is set to false when the toolbar is used above the keyboard without the container view
//we need to set it to true again or else the toolbar will appear at the very top of the window instead of the bottom if the keyboard has previously been shown.
toolbar.translatesAutoresizingMaskIntoConstraints=true
toolbarContainerView?.addSubview(toolbar)
}
return toolbarContainerView
}
It would probably be a good idea to override viewSafeAreaInsetsDidChange to adjust the size of toolbarContainerView in that case, too.