Does anyone know how to change the input keyboard type for the searchbar? The code
searchController.searchBar.inputView = input
doesn't work like in a text field. I have read that the subview of the searchBar is a textfield but I don't know how to access that subview to change the inputView.
I think you want to display different keyboard than standard,
Make sure you have assign delegate to keyboard.
class ViewController: UIViewController, UISearchBarDelegate, KeyboardDelegate
{
#IBOutlet weak var searchBar: UISearchBar!
override func viewDidLoad() {
let keyboardView = KeyboardView(frame: CGRect(x: 0, y: 0, width: 375, height: 165))
keyboardView.delegate = self
let searchTextField = searchBar.value(forKey: "_searchField") as! UITextField
searchTextField.inputView = keyboardView
}
func keyWasTapped(text: String) {
searchBar.text = text
}
}
My Custom Keyboard Class
protocol KeyboardDelegate: class {
func keyWasTapped(text: String)
}
class KeyboardView: UIView {
// This variable will be set as the view controller so that
// the keyboard can send messages to the view controller.
weak var delegate: KeyboardDelegate?
// MARK:- keyboard initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeSubviews()
}
func initializeSubviews() {
let xibFileName = "KeyboardView" // xib extention not included
let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)?[0] as! UIView
self.addSubview(view)
view.frame = self.bounds
}
// MARK:- Button actions from .xib file
#IBAction func keyTapped(_ sender: UIButton) {
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
self.delegate?.keyWasTapped(text: sender.titleLabel!.text!) // could alternatively send a tag value
}
}
You have to access like this :
if let searchBarTxtField = searchController.searchBar.valueForKey("_searchField") as UITextField {
searchBarTxtField.inputView = input
}
Related
I created a custom input accessory view, it is the submit button.
However, I need to pass the data to the custom view then execute the further function. It is a good way to do that?
class SignUpViewController: UIViewController {
#IBOutlet weak var phoneTF: SignLogTextField!
#IBOutlet weak var EmailTF: SignLogTextField!
#IBOutlet weak var PasswordTF: SignLogTextField!
#IBOutlet weak var FBBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
textFieldPreparation()
}
func textFieldPreparation(){
EmailTF.inputAccessoryView = Bundle.main.loadNibNamed("SignSubmitBTN", owner: self, options: nil)?.first as! SignSubmitBTN
phoneTF.inputAccessoryView = Bundle.main.loadNibNamed("SignSubmitBTN", owner: self, options: nil)?.first as! SignSubmitBTN
PasswordTF.inputAccessoryView = Bundle.main.loadNibNamed("SignSubmitBTN", owner: self, options: nil)?.first as! SignSubmitBTN
}
}
I am not sure how to pass the data to the custom view or should I do the sign up in the Outlet Action?
It is my custom view
import UIKit
class SignSubmitBTN: UIView {
#IBAction func submitAction(_ sender: Any) {
}
#IBOutlet weak var subBTN: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup(){}
}
If I have to pass data to custom view should I use protocol? If I should use the protocol of how to use it?
OK...
I think you are approaching this from the wrong direction. The responsibility of a button should be to tell you that a user has tapped it and nothing more. The button should not be dealing with signing in.
But... you are 90% of the way there here. Just a few more bits to add.
You can update your submit button to include a delegate and use the delegate in your button action...
import UIKit
// protocol
protocol SignInButtonDelegate: class {
func signIn()
}
class SignSubmitBTN: UIView {
// property for delegate
weak var delegate: SignInButtonDelegate?
#IBAction func submitAction(_ sender: Any) {
// this tells the delegate to sign in
// it doesn't need to know how that happens
delegate?.signIn()
}
#IBOutlet weak var subBTN: UIButton!
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {}
}
Then in your view controller you conform to the delegate protocol...
extension SignUpViewController: SignInButtonDelegate {
func signIn() {
// here you already have access to all the data you need to sign in.
// you are in the view controller here so just get the text from the username, password, etc...
}
}
And then set the view controller as the delegate...
func textFieldPreparation() {
let signInButton = Bundle.main.loadNibNamed("SignSubmitBTN", owner: self, options: nil)?.first as! SignSubmitBTN
signInButton.delegate = self
// these are properties... they should begin with a lowercase letter
emailTF.inputAccessoryView = signInButton
phoneTF.inputAccessoryView = signInButton
passwordTF.inputAccessoryView = signInButton
}
Your CustomView is just a class at the end, so you can do it in object oriented paratime, For that write a function in your customView to pass data in it. Like
class SignSubmitBTN: UIView {
var data: String!;
public func setData(data: String) {
self.data = data;
}
/// Other code
}
And to set data after initializing your CustomView, call setData(params) function to set data in it.
Try this
func loadFromNib() -> SignSubmitBTN {
let bundle = Bundle.main.loadNibNamed("SignSubmitBTN", owner: self, options: nil)?.first as! SignSubmitBTN
return bundle
}
In your viewcontroller call like below:
let customObj = loadFromNib()
customObj.dataToGet = "Data to pass"
customObj.delegate = self
EmailTF.inputAccessoryView = customObj
If you want pass data from custom class, You need to use delegate protocol as #Fogmeister suggested.
If you want delegate option
public protocol menuOpen: class {
func openMenuAction(selectedValue : String)
}
class SignSubmitBTN: UIView {
open var delegate:menuOpen?
var dataToGet = ""
#IBAction func submitAction(_ sender: Any) {
self.delegate.openMenuAction("test")
}
}
Then add delegate method in your VC
class SignUpViewController: UIViewController,menuOpen{
func openMenuAction(selectedValue : String) {
//get your selected value here, you would better pass parameter in this method
}
}
I have an app where there is a "DadViewController" which contains a UIScrollView that has paging enabled. Each page is populated with a different UIViewController.
How Do I push a new UIViewController, from a button tap, within one of the controllers contained in the UIScrollView?
class DadView: UIView {
let model = DadModel()
let scrollView: UIScrollView = {
let view = UIScrollView()
view.isPagingEnabled = true
// Additional setup...
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupScrollView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupScrollView() {
self.addSubview(scrollView)
// Autolayout code to pin scrollview to all 4 sides
let vc1 = VC1()
scrollView.addSubview(vc1.view)
vc1.view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
// Add additional view controller views with the appropriate frames...
}
}
class DadController: UIViewController {
var dadView: DadView!
override func loadView() {
super.loadView()
dadView = DadView()
view = dadView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
class VC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
}
Change your DadView setupScrollView to accept a UIViewController instance as argument. And don't call this method in init
class DadView: UIView {
let model = DadModel()
let scrollView: UIScrollView = {
let view = UIScrollView()
view.isPagingEnabled = true
// Additional setup...
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
// setupScrollView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
fileprivate func setupScrollView(_ parentVC: UIViewController) {
self.addSubview(scrollView)
// Autolayout code to pin scrollview to all 4 sides
let vc1 = VC1()
vc1.view.frame = CGRect(x: 0, y: 0, width: SCREEN_WIDTH, height: SCREEN_HEIGHT)
parentVC.addChild(vc1)
scrollView.addSubview(vc1.view)
vc1.didMove(toParent: parentVC)
// Add additional view controller views with the appropriate frames...
}
}
In DadViewController after creating DadView instance call setupScrollView method with self
class DadController: UIViewController {
var dadView: DadView!
override func loadView() {
super.loadView()
dadView = DadView()
dadView.setupScrollView(self)
view = dadView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Then you can get parent view controller from child viewcontroller and perform push
class VC1: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
#IBAction func buttonAction(_ sender: UIButton) {
self.parent?.navigationController?.pushViewController(NewVC(), animated: true)
}
}
I need to open keyboard on button click for UIButton (not using/for UITextField). I have tried to create custom button by overriding variable canBecomeFirstResponder but it's not working.
Is there any other way to do so?
Note: I want to set UIPIckerView as an input view of UIButton in key board frame.
Here is my code.
class RespondingButton: UIButton {
override var canBecomeFirstResponder: Bool {
return true
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
// common init
}
}
In my view controller, I connected button action.
class TestViewController: UIViewController {
#IBAction func testBecomeFirstResponder(button: RespondingButton){
button.becomeFirstResponder() // Not working.
}
}
Here is what I would do.
Create transparent textField 1x1px, lets say it is myTextField.
Then add your desired button. In the button action make the myTextField.becomeFirstResponder().
Create view:
let pvBackground: UIView = {
let v = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
v.backgroundColor = .white
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
In viewDidLoad:
pvBackground.addSubview(yourPickerView)//add the picker into the pvBackground
myTextField.inputView = pvBackground
I added the pickerView into the another view to be able to customize it more.
Add conformance to UIKeyInput like this. It should work.
class RespondingButton: UIButton, UIKeyInput {
override var canBecomeFirstResponder: Bool {
return true
}
var hasText: Bool = true
func insertText(_ text: String) {}
func deleteBackward() {}
}
Since standard Number Pad keyboard has "empty" button, but doesn't have "+/-" button, I decided to create my own Keyboard Extension. I've done it.
But I don't know how to link (and invoke) it with a particular Text Field while other Text Fields using usual keyboards.
Is there any opportunity to apply custom keyboardType like my own custom Keyboard?
I found solution based on simular question: How to input text using the buttons of an in-app custom keyboard
import UIKit
protocol KeyboardDelegate: class {
func keyWasTapped(text: String)
}
class KeyboardView: UIView {
// This variable will be set as the view controller so that
// the keyboard can send messages to the view controller.
weak var delegate: KeyboardDelegate?
// MARK:- keyboard initialization
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initializeSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initializeSubviews()
}
func initializeSubviews() {
let xibFileName = "KeyboardView" // xib extention not included
let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)?[0] as! UIView
self.addSubview(view)
view.frame = self.bounds
}
// MARK:- Button actions from .xib file
#IBAction func keyTapped(_ sender: UIButton) {
// When a button is tapped, send that information to the
// delegate (ie, the view controller)
self.delegate?.keyWasTapped(text: sender.titleLabel!.text!) // could alternatively send a tag value
}
}
/* when error: "Could not load NIB in bundle"
Could not load NIB in bundle
Visit the properties of the .xib files in the file inspector ,the property "Target Membership" pitch on the select box ,then your xib file was linked with your target
*/
In main ViewController.swift
import UIKit
class ViewController: UIViewController, UITextFieldDelegate, KeyboardDelegate {
#IBOutlet weak var text1: UITextField!
#IBOutlet weak var text2: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// initialize custom keyboard
let keyboardView = KeyboardView(frame: CGRect(x: 0, y: 0, width: 375, height: 165))
keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped
// replace system keyboard with custom keyboard
text1.inputView = keyboardView //accessoryView
text1.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// required method for keyboard delegate protocol
func keyWasTapped(text character: String) {
if Int(character) != nil{
text1.insertText(character)
}
if character == "⌫" {
if !(text1.text?.isEmpty)! {
let beforeText = text1.text!
let truncated = beforeText.substring(to: beforeText.index(before: beforeText.endIndex))
text1.text = truncated
}
}
if character == "±" {
let beforeText = text1.text!
if var number = Int(beforeText) {
number = -number
text1.text = "\(number)"
}
}
}
func textFieldDidBeginEditing(_ textField: UITextField) {
/*
if (textField == self.text1) {
//textField.inputView = keyboardView
}
*/
}
}
I have coded a calculator for metric/imperial system. For that, I have coded my own keyboard, too.
I have set up the keyboard as UIButtons stacked within a Stack View.
The Buttons seem to be unknown for Xcode since I have just upgraded to Xcode 8 and the project is still in Swift 2.2.
Then I have set a UITextField and filled its text property using my buttons. This is for example the function for the Button 1 on my keyboard.
#IBOutlet weak var inputField: UITextField!
var numberStr:String = "0"
inputField.text = numberStr
#IBAction func oneKeyboardAction(sender: AnyObject) {
if numberStr == "0" {
numberStr = String(numberStr.characters.dropLast())
}
let newStr:String = numberStr + String("1")
numberStr = newStr
let dotToCommaString = newStr.stringByReplacingOccurrencesOfString(".", withString: ",")
inputField.text = dotToCommaString
}
Also I have deactivated user interaction with the TextField, so the "original Keyboard" will not show.
Edit
Like mentioned in the comment section and to have my answer better fit your needs. You could set my custom keyboard into a UIView overlapping your UIViewController inside the Interface Builder. Set it as MyKeyboardView.hidden = true inside the viewDidLoad().
Then you have your TextField where you want the custom Keyboard to be visible instead of the system one:
func textFieldDidBeginEditing(_ textField: UITextField) {
if (textField == self.yourDesiredTextField) { //the one where you want to use the custom keyboard
MyKeyboardView.hidden = false
}
}
Then you add a gesture recognizer like that:
override func viewDidLoad() {
super.viewDidLoad()
MyKeyboardView.hidden = true
let tap = UITapGestureRecognizer(target: self, action: #selector(gesture))
tap.numberOfTapsRequired = 1
view.addGestureRecognizer(tap)
}
func gesture() {
UIView.animateWithDuration(0.2) {
self.MyKeyboardView.hidden = true
}
}
To have it little more smooth, I have added animateWithDuration when hiding the keyboard.
I am trying to create a custom UIView and display it as a pop up in my main View using Swift.
My Custom UIView code is
class DatePopUpView: UIView {
var uiView:UIView?
override init() {
super.init()
self.uiView = NSBundle.mainBundle().loadNibNamed("DatePopUpView", owner: self, options: nil)[0] as? UIView
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
required override init(frame: CGRect) {
super.init(frame: frame)
}
}
And I am Calling it in my main view as:
#IBAction func date_button_pressed (sender : AnyObject?) {
var popUpView = DatePopUpView()
var centre : CGPoint = CGPoint(x: self.view.center.x, y: self.view.center.y)
popUpView.center = centre
popUpView.layer.cornerRadius = 10.0
let trans = CGAffineTransformScale(popUpView.transform, 0.01, 0.01)
popUpView.transform = trans
self.view .addSubview(popUpView)
UIView .animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
popUpView.transform = CGAffineTransformScale(popUpView.transform, 100.0, 100.0)
}, completion: {
(value: Bool) in
})
}
But popUp is not Coming. I used breakpoint and noticed that value is getting assigned to my popUpView but still it is not displayed on my main View. Please Help
Please Note: I am using StoryBoard for my mainView and custom View i have made using xib.
Without additional description on what you are attempting to do, may I suggest something like the code below? Basically, you can use .hidden feature of a view (or any other control) to show/hide the view. You can set the size and positioning of the view to be popped by using the layout editor.
import UIKit
class ViewController: UIViewController {
var popped = false
var popupBtnTitle = "Show Popup"
#IBAction func popupButton(sender: UIButton) {
popped = !popped
anotherView.hidden = !popped
popupBtnTitle = popped ? "Hide Popup" : "Show Popup"
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
}
#IBOutlet weak var popupButtonOutlet: UIButton!
#IBOutlet weak var anotherView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
popped = false
anotherView.hidden = !popped
popupButtonOutlet.setTitle(popupBtnTitle, forState: UIControlState.Normal)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}