gmertk / ParkedTextField

A text field with a constant text/placeholder

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add option for parkedText in the beginning

gmertk opened this issue · comments

Ah! I came here to request this. Glad it's on the radar, I specifically would like to use this for currency text fields where the currency symbol is parked at the beginning.

Yep will fix it soon. And already got a pull request for it. 👍

Yeah! Waiting for this as well!

I thought this was going to be easy. But there is a problem with moving the cursor in the placeholder as seen in #6. When there is no text written in the text field, the attributedPlaceholder takes its place. And I couldn't find a way to move the cursor to the end of the preceding parked text.

I guess one solution is to stop using placeholder, and to use the text property only. So, the cursor can be moved as needed. Will try and let you know.

It's definitely not easy, it especially get's difficult when the user moves the cursor around and copy/pastes

I am not sure if this helps at all, but I built this to handle some "live formatting" of text fields. Specifically for credit card number fields where we wanted the 1234 1234 1234 1234 for cards that have that grouping and 1234 123456 12345 for AMEX.

import UIKit

protocol StringFormatter {
    func formattedString(string: String) -> String
}

@objc
protocol FormattedTextFieldForwardingDelegate: NSObjectProtocol {
    optional func textFieldShouldBeginEditing(textField: UITextField) -> Bool
    optional func textFieldDidBeginEditing(textField: UITextField)
    optional func textFieldShouldEndEditing(textField: UITextField) -> Bool
    optional func textFieldDidEndEditing(textField: UITextField)
    optional func textFieldShouldClear(textField: UITextField) -> Bool
    optional func textFieldShouldReturn(textField: UITextField) -> Bool
    optional func textFieldValueDidChange(textField: UITextField)
}


/// Provides a mechanism to do live formatting of a `UITextField`, most `UITextFieldDelegate` methods are forwarded on through the `forwardingDelegate` property.
final class FormattedTextFieldDelegate: NSObject, UITextFieldDelegate {

    /// Use a forwarding delegate to receive forwarded `UITextFieldDelegate` calls that this delegate intercepts.
    ///
    /// This takes complete control over `textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String)` so that call is not forwarded.
    var forwardingDelegate: FormattedTextFieldForwardingDelegate?

    /// The formatter to use as the text field is being typed in.
    let formatter: StringFormatter

    /// Character set that can be typed into the `UITextField`.
    ///
    /// Note: The provided `formatter` has the opportunity to replace the text field's value with characters outside of the provided set.
    let allowedTypedCharacterSet: NSCharacterSet?

    init(formatter: StringFormatter, allowedTypedCharacterSet: NSCharacterSet? = nil) {
        self.formatter = formatter
        self.allowedTypedCharacterSet = allowedTypedCharacterSet
    }

    func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
        return forwardingDelegate?.textFieldShouldBeginEditing?(textField) ?? true
    }

    func textFieldDidBeginEditing(textField: UITextField) {
        forwardingDelegate?.textFieldDidBeginEditing?(textField)
    }

    func textFieldShouldEndEditing(textField: UITextField) -> Bool {
        return forwardingDelegate?.textFieldShouldEndEditing?(textField) ?? true
    }

    func textFieldDidEndEditing(textField: UITextField) {
        forwardingDelegate?.textFieldDidEndEditing?(textField)
    }

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

        if let allowedTypedCharacterSet = allowedTypedCharacterSet where string.rangeOfCharacterFromSet(allowedTypedCharacterSet.invertedSet) != nil {
            return false
        }

        let beginning = textField.beginningOfDocument
        let cursorLocation = textField.positionFromPosition(beginning, offset: (range.location + count(string)))
        let originalTextFieldText = textField.text
        textField.text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)

        let formattedString = formatter.formattedString(textField.text)
        textField.text = formattedString

        if cursorLocation != nil {
            textField.selectedTextRange = textField.textRangeFromPosition(cursorLocation, toPosition: cursorLocation)
        }

        forwardingDelegate?.textFieldValueDidChange?(textField)
        return false
    }

    func textFieldShouldClear(textField: UITextField) -> Bool {
        return forwardingDelegate?.textFieldShouldClear?(textField) ?? true
    }

    func textFieldShouldReturn(textField: UITextField) -> Bool {
        return forwardingDelegate?.textFieldShouldReturn?(textField) ?? true
    }
}

You create an instance of one of these and assign to as the textfield's delegate, then if you need to receive the other delegate calls you can assign whatever needs to handle those as the forwardingDelegate