How to go back when the UITextfield is empty in Swift code? - ios

My question is: When the UITextField is empty, how do I click the "Backspace" button to go to the previous UITextField? I have been struggling trying to do this in my code below?
Second Question: How do I only allow 1 character to get entered in the UITextField?
I am new at Swift code and trying to learn. Any help would be great.
What I am trying to do is have the user be able to type in a code in the 6 UITextFields and be able to click the "Backspace" button on any one of the UITextFields with only allowing the user to enter one number in each UITextField.
Code Below:
#objc func textFieldDidChange(textfield: UITextField) {
let text = textfield.text!
if text.utf16.count == 0 {
switch textfield {
case textField2:
textField1.becomeFirstResponder()
textField1.backgroundColor = UIColor.blue
textField1.tintColor = .clear
case textField3:
textField2.becomeFirstResponder()
textField2.backgroundColor = UIColor.blue
textField2.tintColor = .clear
case textField4:
textField3.becomeFirstResponder()
textField3.backgroundColor = UIColor.blue
textField3.tintColor = .clear
case textField5:
textField4.becomeFirstResponder()
textField4.backgroundColor = UIColor.blue
textField4.tintColor = .clear
case textField6:
textField5.becomeFirstResponder()
textField5.backgroundColor = UIColor.blue
textField5.tintColor = .clear
textField6.resignFirstResponder()
textField6.backgroundColor = UIColor.blue
textField6.tintColor = .clear
default:
break
}
}
else if text.utf16.count == 1 {
switch textfield {
case textField1:
textField1.backgroundColor = UIColor.black
textField1.textColor = .white
textField1.tintColor = .clear
textField2.becomeFirstResponder()
textField2.backgroundColor = UIColor.black
textField2.textColor = .white
textField2.tintColor = .clear
case textField2:
textField3.becomeFirstResponder()
textField3.backgroundColor = UIColor.black
textField3.textColor = .white
textField3.tintColor = .clear
case textField3:
textField4.becomeFirstResponder()
textField4.backgroundColor = UIColor.black
textField4.textColor = .white
textField4.tintColor = .clear
case textField4:
textField5.becomeFirstResponder()
textField5.backgroundColor = UIColor.black
textField5.textColor = .white
textField5.tintColor = .clear
case textField5:
textField6.becomeFirstResponder()
textField6.backgroundColor = UIColor.black
textField6.textColor = .white
textField6.tintColor = .clear
case textField6:
textField6.resignFirstResponder()
default:
break
}
}
}

I'd just like to point out that I'm still relatively new to iOS and Swift in general, but even with just a few minutes of searching, I was able to find some seeds of ideas which provided me with the suggested solution.
Based on your (improved) question, I believe a different approach is required. What you really don't want to use a text component. "Why"?
I here you ask. Because they don't actually provide you with the functionality that you want and come with a considerable overhead.
For this, what you really want is more control. You want to know when a key is pressed and you want to respond to it (I know, sounds like a text component, but) and be notified when more extended functionality occurs, like the delete key is pressed.
After a few minutes of research, some trial and error, I found that the UIKeyInput is more along the lines of what you want.
It will tell you when text is inserted and, more importantly, will tell you when Delete is pressed
The added benefit is, you can filter the input directly. You can take the first character from the String and ignore the rest or auto fill the following elements with the remaining text. You can perform validation (for numerical only content) and what ever else you might want to do
So, I started a really new project, added a UILabel to the UIViewController in the storyboard, bound it to the source and implemented the UIKeyInput protocol as such...
class ViewController: UIViewController {
override var canBecomeFirstResponder: Bool {
return true
}
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
becomeFirstResponder()
}
}
extension ViewController: UIKeyInput {
var hasText: Bool {
return true
}
func insertText(_ text: String) {
print(text)
label.text = text
}
func deleteBackward() {
print("Delete backward")
}
}
I ran the project and when a key was typed, the label was updated with the new key and when delete was pressed, the Delete backward text was printed to console.
Now. You have some choices to make. To use a single UIViewController and (maybe) a series of UILabels and manage interactions within it, so when a key is typed, you present the next label as the input focus (and when delete is pressed, you move back) or do you create a series of UIControls which represent each digit and manage via some delegate call back process.
You may also need to implement the UITextInputTraits protocol, which will allow you to control the keyboard presented
You might also like to have a read through Responding to Keyboard Events on iOS, CustomTextInputView.swift and Showing the iOS keyboard without a text input which were just some of the resources I used to hobble this basic example together with.

you can use this extension for your second question:
import UIKit
private var maxLengths = [UITextField: Int]()
extension UITextField {
#IBInspectable var maxLength: Int {
get {
guard let length = maxLengths[self] else {
return Int.max
}
return length
}
set {
maxLengths[self] = newValue
addTarget(
self,
action: #selector(limitLength),
for: UIControlEvents.editingChanged
)
}
}
#objc func limitLength(textField: UITextField) {
guard let prospectiveText = textField.text,
prospectiveText.count > maxLength
else {
return
}
let selection = selectedTextRange
let maxCharIndex = prospectiveText.index(prospectiveText.startIndex, offsetBy: maxLength)
text = prospectiveText.substring(to: maxCharIndex)
selectedTextRange = selection
}
}
when you add this extension to your project you can see an extra attribute in "Attribute Inspector" tab and you can set the max length of UITextField.

Related

Swift UITextView Delegate

I am having a problem and have searched all across StackO and did not see a solution.
I have a UITextview extension with TextViewDelegate that I call inside of my VC so that i can have a placeholder label. The problem is i now need to add a func that checks for remaining chars in that same textView which i am able to get to work properly. But i cant grab a label to present it on the VC from that extension. I have been trying delegates but since it is a delegate itself i cant use my normal methods. What is the best route to go about this? Thank You for your help!
Here is the code. The placeholder label code is left out since it will make everything longer and I do not feel its needed for a solution. But I can add if necessary. And i can not move this code straight into VC as i need this extension to stay like this.
extension UITextView: UITextViewDelegate {
/// When the UITextView change, show or hide the label based on if the UITextView is empty or not
public func textViewDidChange(_ textView: UITextView) {
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderLabel.isHidden = !self.text.isEmpty
}
checkRemainingChars(textView: textView)
}
func checkRemainingChars(textView: UITextView) {
let allowedChars = 140
if let charsInTextField = textView.text?.count {
let charsInLabel = charsInTextField
let remainingChars = charsInLabel
if remainingChars <= allowedChars {
//Need to grab this label
charsLeftLabel.textColor = UIColor.lightGray
}
if remainingChars >= 120 {
//Need to grab this label
charsLeftLabel.textColor = UIColor.orange
}
if remainingChars >= allowedChars {
//Need to grab this label
charsLeftLabel.textColor = UIColor.red
}
//This prints fine
print("Remaining chars is \(remainingChars)/140")
//Need to grab this label
charsLeftLabel.text = String(remainingChars)
}
}
Thanks again.

textfield.becomeFirstResponder isn't keeping text field focused in swift

I have a page where there is a UITextField that I add programmatically, I set the text type to number and add constraints and all that. Then I add a done button to the accessoryView of the text field and add a function to run when that done button is pressed. My problem is, when the page loads, I want the text field to be focused and the keyboard shown. I set the becomeFirstResponder on it, but when the page loads, the keyboard shows up for a split second then immediately disappears and the delegate methods are run.
I need to find a way to make the text field "active", "focused", whatever you want to call it when the page loads, and for the keyboard to be there and ready. I can't seem to find any help aside from call becomeFirstResponder on it, which only works for a split second.
Here is the code I am using to build the page and run everything, I simplified it to reduce clutter and read times, but if you need more info, please let me know and I will be happy to provide the full code...
class AgeViewController: UIViewController {
var selectedAge: Int = 0
var textInput: UITextField!
let settings = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
createPage()
}
override func viewWillAppear(_ animated: Bool) {
textInput.becomeFirstResponder()
//I have tried this in both viewWillAppear and viewDidAppear
}
func createPage() {
textInput = UITextField()
textInput.font = .systemFont(ofSize: 50)
textInput.placeholder = "35"
textInput.borderStyle = .none
textInput.keyboardType = .numberPad
textInput.returnKey = .done
textInput.textAlignment = .right
addDoneButton()
textInput.delegate = self
view.addSubView(textInput)
//create a label and add it to the page
}
private fun addDoneButton() {
let doneToolbar: UIToolbar = 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 = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(doneTapped))
let items = [flexSpace, done]
doneToolbar.sizeToFit()
textInput.inputAccessoryView = doneToolbar
}
#objc func doneTapped() {
textInput.resignFirstResponder()
}
}
extension AgeViewController: UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
textField.textColor = UIColor(named: "text")!
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
if textField.text != nil {
selectedAge = Int(textField.text!) ?? 35
settings.set(selectedAge, forKey: Strings.age)
} else {
textField.textColor = UIColor(named: "grayText")!
}
}
Like I said, the page loads, the keyboard shows up for a split second, then goes away and the delegate methods are called for didEndEditing. I don't understand why it isn't staying focused, I am calling becomeFirstResponder. I have tried calling textInput.becomeFirstResponder() in 3 different places, all with the same result. The first was right after I add the subview to the view, then I tried in viewDidAppear and finally in viewWillAppear, all have the same result, shows up for a split second, then goes away. Sorry for the long post, thank you for any help, I really appreciate it.

Alternate UIView background between two colors by pressing a button

I'm trying to set up one button that each time pressed would alternate between two colours (black and white).
Initially the app loads with a black background, with the first button tap it swaps to a white background, with the second tap it swaps back to a black background and so fourth.
I imagine it would be a simple if else statement, however I don't know how to create a variable that is the current UI background colour.
#IBAction func background_toggle(_ sender: UIButton) {
self.view.backgroundColor = UIColor.white
}
The button swaps it to white, but there isn't any implementation to swap back to black when there is a second press.
You can use backgroundColor as a condition to check which one you should pick next.
Approach using a backgroundColor attribute
#IBAction func background_toggle(_ sender: UIButton) {
if self.view.backgroundColor == .white {
self.view.backgroundColor = .black
} else {
self.view.backgroundColor = .white
}
}
In other words: If backgroundColor is .white, then set it .black
Otherwise, set it .white
Tips:
Since backgroundColor is an UIColor, Swift infers the type, so you can just type .white or .black when assigning it, without having to specify UIColor.white or UIColor.black.
You can have a state variable like a Bool, UIColor or Enum. Then you compare to that instead of the backgroundColor of the view.
Approach using a Bool variable
var isWhite = true
#objc func handleOpenTermsAndConditions() {
if self.isWhite {
self.isWhite = false
self.view.backgroundColor = .black
} else {
self.isWhite = true
self.view.backgroundColor = .white
}
}
Approach using an UIColor variable
var currentBackgroundColor : UIColor = .white
#objc func handleOpenTermsAndConditions() {
if currentBackgroundColor == .white {
self.currentBackgroundColor = .black
self.view.backgroundColor = .black
} else {
self.currentBackgroundColor = .white
self.view.backgroundColor = .white
}
}
Approach using an Enum state
If you want to restrict colors you can create an Enum with available colors. I think it's overkill to use it with some logic that is as simple as .white | .black.
Step 1: Create an enum.
enum AvailableColor {
case white
case black
func currentUIColor() -> UIColor {
switch self {
case .white:
return UIColor.white
case .black:
return UIColor.black
}
}
}
Step 2: Instantiate a state variable and use the enum logic
var currentColorState : AvailableColor = .white
#objc func handleOpenTermsAndConditions() {
if currentColorState == .white {
currentColorState = .black
} else {
currentColorState = .white
}
self.view.backgroundColor = currentColorState.currentUIColor()
}
Don't try to use the contents of the view to determine the next state by comparing the colors.
Separate out your model from your view and keep a separate property that has the current state. You could use a simple boolean flag isBlack, or you could create an enumeration:
enum BackgroundState {
case black, white
}
which has the slight advantage of being easier to expand if you ever want another color/state. (CaseIterable might be helpful then as well.)

A Swift example of Custom Views for Data Input (custom in-app keyboard)

Goal
I want to make a custom keyboard that is only used within my app, not a system keyboard that needs to be installed.
What I have read and tried
Documentation
App Extension Programming Guide: Custom Keyboard
Custom Views for Data Input
The first article above states:
Make sure a custom, systemwide keyboard is indeed what you want to
develop. To provide a fully custom keyboard for just your app or to
supplement the system keyboard with custom keys in just your app, the
iOS SDK provides other, better options. Read about custom input views
and input accessory views in Custom Views for Data Input in Text
Programming Guide for iOS.
That is what led me to the second article above. However, that article did not have enough detail to get me started.
Tutorials
iOS 8: Creating a Custom Keyboard in Swift
How to make a custom keyboard in iOS 8 using Swift
Xcode 6 Tutorial: iOS 8.0 Simple Custom Keyboard in Swift
Creating a Custom Keyboard Using iOS 8 App Extension
I was able to get a working keyboard from the second tutorial in the list above. However, I couldn't find any tutorials that showed how to make an in app only keyboard as described in the Custom Views for Data Input documentation.
Stack Overflow
I also asked (and answered) these questions on my way to answering the current question.
How to input text using the buttons of an in-app custom keyboard
Delegates in Swift
Question
Does anyone have a minimal example (with even one button) of an in app custom keyboard? I am not looking for a whole tutorial, just a proof of concept that I can expand on myself.
This is a basic in-app keyboard. The same method could be used to make just about any keyboard layout. Here are the main things that need to be done:
Create the keyboard layout in an .xib file, whose owner is a .swift file that contains a UIView subclass.
Tell the UITextField to use the custom keyboard.
Use a delegate to communicate between the keyboard and the main view controller.
Create the .xib keyboard layout file
In Xcode go to File > New > File... > iOS > User Interface > View to create the .xib file.
I called mine Keyboard.xib
Add the buttons that you need.
Use auto layout constraints so that no matter what size the keyboard is, the buttons will resize accordingly.
Set the File's Owner (not the root view) to be the Keyboard.swift file. This is a common source of error. See the note at the end.
Create the .swift UIView subclass keyboard file
In Xcode go to File > New > File... > iOS > Source > Cocoa Touch Class to create the .swift file.
I called mine Keyboard.swift
Add the following code:
import UIKit
// The view controller will adopt this protocol (delegate)
// and thus must contain the keyWasTapped method
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
}
class Keyboard: 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 = "Keyboard" // 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(character: sender.titleLabel!.text!) // could alternatively send a tag value
}
}
Control drag from the buttons in the .xib file to the #IBAction method in the .swift file to hook them all up.
Note that the protocol and delegate code. See this answer for a simple explanation about how delegates work.
Set up the View Controller
Add a UITextField to your main storyboard and connect it to your view controller with an IBOutlet. Call it textField.
Use the following code for the View Controller:
import UIKit
class ViewController: UIViewController, KeyboardDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// initialize custom keyboard
let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 300))
keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped
// replace system keyboard with custom keyboard
textField.inputView = keyboardView
}
// required method for keyboard delegate protocol
func keyWasTapped(character: String) {
textField.insertText(character)
}
}
Note that the view controller adopts the KeyboardDelegate protocol that we defined above.
Common error
If you are getting an EXC_BAD_ACCESS error, it is probably because you set the view's custom class as Keyboard.swift rather than do this for the nib File's Owner.
Select Keyboard.nib and then choose File's Owner.
Make sure that the custom class for the root view is blank.
The key is to use the existing UIKeyInput protocol, to which UITextField already conforms. Then your keyboard view need only to send insertText() and deleteBackward() to the control.
The following example creates a custom numeric keyboard:
class DigitButton: UIButton {
var digit: Int = 0
}
class NumericKeyboard: UIView {
weak var target: (UIKeyInput & UITextInput)?
var useDecimalSeparator: Bool
var numericButtons: [DigitButton] = (0...9).map {
let button = DigitButton(type: .system)
button.digit = $0
button.setTitle("\($0)", for: .normal)
button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
button.setTitleColor(.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.darkGray.cgColor
button.accessibilityTraits = [.keyboardKey]
button.addTarget(self, action: #selector(didTapDigitButton(_:)), for: .touchUpInside)
return button
}
var deleteButton: UIButton = {
let button = UIButton(type: .system)
button.setTitle("⌫", for: .normal)
button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
button.setTitleColor(.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.darkGray.cgColor
button.accessibilityTraits = [.keyboardKey]
button.accessibilityLabel = "Delete"
button.addTarget(self, action: #selector(didTapDeleteButton(_:)), for: .touchUpInside)
return button
}()
lazy var decimalButton: UIButton = {
let button = UIButton(type: .system)
let decimalSeparator = Locale.current.decimalSeparator ?? "."
button.setTitle(decimalSeparator, for: .normal)
button.titleLabel?.font = .preferredFont(forTextStyle: .largeTitle)
button.setTitleColor(.black, for: .normal)
button.layer.borderWidth = 0.5
button.layer.borderColor = UIColor.darkGray.cgColor
button.accessibilityTraits = [.keyboardKey]
button.accessibilityLabel = decimalSeparator
button.addTarget(self, action: #selector(didTapDecimalButton(_:)), for: .touchUpInside)
return button
}()
init(target: UIKeyInput & UITextInput, useDecimalSeparator: Bool = false) {
self.target = target
self.useDecimalSeparator = useDecimalSeparator
super.init(frame: .zero)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
// MARK: - Actions
extension NumericKeyboard {
#objc func didTapDigitButton(_ sender: DigitButton) {
insertText("\(sender.digit)")
}
#objc func didTapDecimalButton(_ sender: DigitButton) {
insertText(Locale.current.decimalSeparator ?? ".")
}
#objc func didTapDeleteButton(_ sender: DigitButton) {
target?.deleteBackward()
}
}
// MARK: - Private initial configuration methods
private extension NumericKeyboard {
func configure() {
autoresizingMask = [.flexibleWidth, .flexibleHeight]
addButtons()
}
func addButtons() {
let stackView = createStackView(axis: .vertical)
stackView.frame = bounds
stackView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addSubview(stackView)
for row in 0 ..< 3 {
let subStackView = createStackView(axis: .horizontal)
stackView.addArrangedSubview(subStackView)
for column in 0 ..< 3 {
subStackView.addArrangedSubview(numericButtons[row * 3 + column + 1])
}
}
let subStackView = createStackView(axis: .horizontal)
stackView.addArrangedSubview(subStackView)
if useDecimalSeparator {
subStackView.addArrangedSubview(decimalButton)
} else {
let blank = UIView()
blank.layer.borderWidth = 0.5
blank.layer.borderColor = UIColor.darkGray.cgColor
subStackView.addArrangedSubview(blank)
}
subStackView.addArrangedSubview(numericButtons[0])
subStackView.addArrangedSubview(deleteButton)
}
func createStackView(axis: NSLayoutConstraint.Axis) -> UIStackView {
let stackView = UIStackView()
stackView.axis = axis
stackView.alignment = .fill
stackView.distribution = .fillEqually
return stackView
}
func insertText(_ string: String) {
guard let range = target?.selectedRange else { return }
if let textField = target as? UITextField, textField.delegate?.textField?(textField, shouldChangeCharactersIn: range, replacementString: string) == false {
return
}
if let textView = target as? UITextView, textView.delegate?.textView?(textView, shouldChangeTextIn: range, replacementText: string) == false {
return
}
target?.insertText(string)
}
}
// MARK: - UITextInput extension
extension UITextInput {
var selectedRange: NSRange? {
guard let textRange = selectedTextRange else { return nil }
let location = offset(from: beginningOfDocument, to: textRange.start)
let length = offset(from: textRange.start, to: textRange.end)
return NSRange(location: location, length: length)
}
}
Then you can:
textField.inputView = NumericKeyboard(target: textField)
That yields:
Or, if you want a decimal separator, too, you can:
textField.inputView = NumericKeyboard(target: textField, useDecimalSeparator: true)
The above is fairly primitive, but it illustrates the idea: Make you own input view and use the UIKeyInput protocol to communicate keyboard input to the control.
Also please note the use of accessibilityTraits to get the correct “Spoken Content” » “Speak Screen” behavior. And if you use images for your buttons, make sure to set accessibilityLabel, too.
Building on Suragch's answer, I needed a done and backspace button and if you're a noob like me heres some errors you might encounter and the way I solved them.
Getting EXC_BAD_ACCESS errors?
I included:
#objc(classname)
class classname: UIView{
}
fixed my issue however Suragch's updated answer seems to solve this the more appropriate/correct way.
Getting SIGABRT Error?
Another silly thing was dragging the connections the wrong way, causing SIGABRT error. Do not drag from the function to the button but instead the button to the function.
Adding a Done Button
I added this to the protocol in keyboard.swift:
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
func keyDone()
}
Then connected a new IBAction from my done button to keyboard.swift like so:
#IBAction func Done(sender: UIButton) {
self.delegate?.keyDone()
}
and then jumped back to my viewController.swift where i am using this keyboard and added this following after the function keyWasTapped:
func keyDone() {
view.endEditing(true)
}
Adding Backspace
This tripped me up a lot, because you must set the textField.delegate to self in the viewDidLoad() method (shown later).
First: In keyboard.swift add to the protocol func backspace():
protocol KeyboardDelegate: class {
func keyWasTapped(character: String)
func keyDone()
func backspace()
}
Second: Connect a new IBAction similar to the Done action:
#IBAction func backspace(sender: UIButton) {
self.delegate?.backspace()
}
Third: Over to the viewController.swift where the NumberPad is appearing.
Important: In viewDidLoad() set all textFields that will be using this keyboard. So your viewDidLoad() should look something like this:
override func viewDidLoad() {
super.viewDidLoad()
self.myTextField1.delegate = self
self.myTextField2.delegate = self
// initialize custom keyboard
let keyboardView = keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 240))
keyboardView.delegate = self // the view controller will be notified by the keyboard whenever a key is tapped
// replace system keyboard with custom keyboard
myTextField1.inputView = keyboardView
myTextField2.inputView = keyboardView
}
I'm not sure how to, if there is a way to just do this to all textFields that are in the view. This would be handy...
Forth: Still in viewController.swift we need to add a variable and two functions. It will look like this:
var activeTextField = UITextField()
func textFieldDidBeginEditing(textField: UITextField) {
print("Setting Active Textfield")
self.activeTextField = textField
print("Active textField Set!")
}
func backspace() {
print("backspaced!")
activeTextField.deleteBackward()
}
Explanation of whats happening here:
You make a variable that will hold a textField.
When the "textFieldDidBeginEditing" is called it sets the variable so it knows which textField we are dealing with. I've added a lot of prints() so we know everything is being executed.
Our backspace function then checks the textField we are dealing with and uses .deleteBackward(). This removes the immediate character before the cursor.
And you should be in business.
Many thanks to Suragchs for helping me get this happening.

textField prevents keyboard showing event

I found a calendarDatePicker here and I want to show that custom picker when user touched textField.
In my previous project I just created a default pickerView and then set it to textField's inputView and it works.
And here I've tried to do this again but THCalendarDatePicker is a viewController, not an inputView.
Here is the code:
class ViewController: UIViewController, THDatePickerDelegate {
#IBOutlet weak var textField: UITextField!
var datePicker:THDatePickerViewController?
var curDate: NSDate?
override func viewDidLoad() {
super.viewDidLoad()
self.curDate = NSDate()
datePicker = THDatePickerViewController.datePicker()
datePicker!.delegate = self
datePicker!.setAllowClearDate(false)
datePicker!.setClearAsToday(true)
datePicker!.setAutoCloseOnSelectDate(false)
datePicker!.setAllowSelectionOfSelectedDate(true)
datePicker!.setDisableHistorySelection(false)
datePicker!.setDisableFutureSelection(false)
//datePicker!.autoCloseCancelDelay = 5.0
datePicker!.selectedBackgroundColor = UIColor.blackColor()
datePicker!.currentDateColor = UIColor.yellowColor()
datePicker!.currentDateColorSelected = UIColor.yellowColor()
}
#IBAction func touchInInput(sender: AnyObject) {
datePicker!.date = curDate
datePicker!.setDateHasItemsCallback({(date:NSDate!) -> Bool in
let tmp = (arc4random() % 30) + 1
return tmp % 5 == 0
})
presentSemiViewController(datePicker!, withOptions: [
KNSemiModalOptionKeys.pushParentBack : NSNumber(bool: true),
KNSemiModalOptionKeys.animationDuration : NSNumber(float: 0.5),
KNSemiModalOptionKeys.shadowOpacity : NSNumber(float: 0.3)
])
sender.inputView == ??? // what I should code here?
}
func datePickerCancelPressed(datePicker: THDatePickerViewController!) {
self.dismissSemiModalView()
}
func datePickerDonePressed(datePicker: THDatePickerViewController!) {
self.dismissSemiModalView()
}
func datePicker(datePicker: THDatePickerViewController!, selectedDate: NSDate!) {
println(selectedDate)
}
}
Can someone help me?
My suggestions would be to
1 programmatically create a container view, populate the container with the view controller, and then try to add that as the inputView for your keyboard.
I have my doubts that would work but it's certainly wouldn't hurt to try.
2 perhaps reconsider your design (if it's your call) and use a pop over view instead that contains your date picker.
Either way let me know how it works out.
Cant you set the datePicker.view value as input view

Resources