Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 55 additions & 16 deletions ParkedTextField/ParkedTextField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import UIKit
public class ParkedTextField: UITextField {

// MARK: Properties
/// Constant part of the text location. Defaults to `true`
@IBInspectable public var parkedTextAtEnd: Bool = true

/// Constant part of the text. Defaults to "".
@IBInspectable public var parkedText: String {
Expand All @@ -19,7 +21,8 @@ public class ParkedTextField: UITextField {
}
set {
if !text.isEmpty {
let typed = text[text.startIndex..<advance(text.endIndex, -count(parkedText))]

let typed = parkedTextAtEnd ? text[text.startIndex..<advance(text.endIndex, -count(parkedText))] : text[parkedText.endIndex..<text.endIndex]
text = typed + newValue

prevText = text
Expand All @@ -31,30 +34,38 @@ public class ParkedTextField: UITextField {
}

// Force update placeholder to get the new value of parkedText
placeholder = placeholderText + parkedText
placeholder = parkedTextAtEnd ? placeholderText + parkedText : parkedText + placeholderText
}
}
var _parkedText = ""

/// Variable part of the text. Defaults to "".
@IBInspectable public var typedText: String {
get {
if text.hasSuffix(parkedText) {
return text[text.startIndex..<advance(text.endIndex, -count(parkedText))]
if parkedTextAtEnd {
if text.hasSuffix(parkedText) {
return text[text.startIndex..<advance(text.endIndex, -count(parkedText))]
} else {
return text
}
} else {
return text
if text.hasPrefix(parkedText) {
return text[parkedText.endIndex..<text.endIndex]
} else {
return text
}
}
}
set {
text = newValue + parkedText
text = (parkedTextAtEnd) ? newValue + parkedText : parkedText + newValue
textChanged(self)
}
}

/// Placeholder before parkedText. Defaults to "".
@IBInspectable public var placeholderText: String = "" {
didSet {
placeholder = placeholderText + parkedText
placeholder = parkedTextAtEnd ? (placeholderText + parkedText) : (parkedText + placeholderText)
}
}

Expand All @@ -80,12 +91,24 @@ public class ParkedTextField: UITextField {
NSForegroundColorAttributeName: parkedTextColor ?? textColor
]
}

var typedTextAttributes: [String: NSObject] {
return [
NSFontAttributeName: self.font,
NSForegroundColorAttributeName: textColor
]
}

public override var placeholder: String? {
didSet {
if let placeholder = placeholder {
let attributedString = NSMutableAttributedString(string: placeholder)
let parkedTextRange = NSMakeRange(count(placeholderText), count(parkedText))
let parkedTextRange: NSRange
if parkedTextAtEnd {
parkedTextRange = NSMakeRange(count(placeholderText), count(parkedText))
} else {
parkedTextRange = NSMakeRange(0, count(parkedText))
}
attributedString.addAttributes(parkedTextAttributes, range: parkedTextRange)
attributedPlaceholder = attributedString
}
Expand All @@ -99,7 +122,9 @@ public class ParkedTextField: UITextField {

var beginningOfConstantText: UITextPosition? {
get {
return positionFromPosition(endOfDocument, offset: -count(parkedText))
return parkedTextAtEnd ?
positionFromPosition(endOfDocument, offset: -count(parkedText))
: beginningOfDocument
}
}

Expand Down Expand Up @@ -141,10 +166,10 @@ public class ParkedTextField: UITextField {
func textChanged(sender: UITextField) {
switch typingState {
case .Start where count(text) > 0:
text = typedText + parkedText
text = parkedTextAtEnd ? typedText + parkedText : parkedText + typedText
updateAttributedTextWith(text)
prevText = text
goToBeginningOfConstantText()
parkedTextAtEnd ? goToBeginningOfConstantText() : goToEndOfText()

typingState = .Typed

Expand All @@ -156,11 +181,17 @@ public class ParkedTextField: UITextField {
}

// Reset to prevText if you tried to change parkedText.
if text.hasSuffix(parkedText) {
prevText = text
if parkedTextAtEnd {
if text.hasSuffix(parkedText) {
prevText = text
}
} else {
if text.hasPrefix(parkedText) {
prevText = text
}
}
updateAttributedTextWith(prevText)
goToBeginningOfConstantText()
parkedTextAtEnd ? goToBeginningOfConstantText() : goToEndOfText()

default:
break
Expand All @@ -170,12 +201,17 @@ public class ParkedTextField: UITextField {

// MARK: Utilites
func updateAttributedTextWith(text: String) {
if let parkedTextRange = text.rangeOfString(parkedText, options: NSStringCompareOptions.BackwardsSearch, range: nil, locale: nil) {
if let parkedTextRange = text.rangeOfString(parkedText, options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil, locale: nil) {
let nsRange = NSRangeFromRange(text, range: parkedTextRange)

let attributedString = NSMutableAttributedString(string: text)
attributedString.addAttributes(parkedTextAttributes, range: nsRange)

if !parkedTextAtEnd {
if let typedTextRange = text.rangeOfString(typedText, options: NSStringCompareOptions.BackwardsSearch, range: nil, locale: nil) {
attributedString.addAttributes(typedTextAttributes, range: NSRangeFromRange(text, range:typedTextRange))
}
}

attributedText = attributedString
}
}
Expand All @@ -193,6 +229,9 @@ public class ParkedTextField: UITextField {
goToTextPosition(position)
}
}
func goToEndOfText() {
goToTextPosition(endOfDocument)
}

func goToTextPosition(textPosition: UITextPosition!) {
selectedTextRange = textRangeFromPosition(textPosition, toPosition: textPosition)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="15A216g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
Expand All @@ -19,6 +19,7 @@
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="9lp-6j-Efe" customClass="ParkedTextField" customModule="ParkedTextFieldExample" customModuleProvider="target">
<rect key="frame" x="16" y="80" width="568" height="33"/>
<animations/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="24"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
Expand All @@ -29,20 +30,23 @@
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9Gr-69-FYt">
<rect key="frame" x="0.0" y="163" width="600" height="150"/>
<subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="0KU-MS-ZWP" customClass="ParkedTextField" customModule="ParkedTextFieldExample" customModuleProvider="target">
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="placeplacplace" textAlignment="center" adjustsFontSizeToFit="NO" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="0KU-MS-ZWP" customClass="ParkedTextField" customModule="ParkedTextFieldExample" customModuleProvider="target">
<rect key="frame" x="16" y="58" width="568" height="33"/>
<animations/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" name="AvenirNext-Regular" family="Avenir Next" pointSize="24"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" spellCheckingType="no"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="parkedText" value="@gmail.com"/>
<userDefinedRuntimeAttribute type="string" keyPath="parkedText" value="beginning@"/>
<userDefinedRuntimeAttribute type="string" keyPath="placeholderText" value="username"/>
<userDefinedRuntimeAttribute type="boolean" keyPath="parkedTextAtEnd" value="NO"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="valueChanged:" destination="vXZ-lx-hvc" eventType="editingChanged" id="ZmG-eL-rvO"/>
</connections>
</textField>
</subviews>
<animations/>
<color key="backgroundColor" red="1" green="0.35686274509803922" blue="0.36470588235294116" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="150" id="17x-cl-a5n"/>
Expand All @@ -53,6 +57,7 @@
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="EZB-Lw-yfM">
<rect key="frame" x="236.5" y="337" width="127" height="40"/>
<animations/>
<fontDescription key="fontDescription" name="AvenirNext-DemiBold" family="Avenir Next" pointSize="20"/>
<state key="normal" title="Set typedText">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
Expand All @@ -64,6 +69,7 @@
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8SL-RM-0Fx">
<rect key="frame" x="230.5" y="380" width="139" height="40"/>
<animations/>
<fontDescription key="fontDescription" name="AvenirNext-DemiBold" family="Avenir Next" pointSize="20"/>
<state key="normal" title="Set parkedText">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
Expand All @@ -74,6 +80,7 @@
</connections>
</button>
</subviews>
<animations/>
<color key="backgroundColor" red="0.38740914125981007" green="0.2828087993922006" blue="0.57809761215092093" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="8SL-RM-0Fx" firstAttribute="centerX" secondItem="EZB-Lw-yfM" secondAttribute="centerX" id="1Ih-zM-YHC"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,21 @@ class ViewController: UIViewController {
slackTextField.parkedText = ".slack.com"
slackTextField.placeholderText = "yourteam"
}

override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// For this to work right, we have to force `didSet` to be called
gmailTextField.placeholderText = "placeholder"
}

@IBAction func valueChanged(sender: ParkedTextField) {
println("text = " + sender.text)
println("typedText = " + sender.typedText)
}

@IBAction func changeParkedText(sender: AnyObject) {
let texts = [".slack.com", "@gmail.com", "@hotmail.com", "@facebook.com"]

// let texts = [".slack.com", "@gmail.com", "@hotmail.com", "@facebook.com"]
let texts = ["beginning", "start", "lawl"]
gmailTextField.parkedText = texts[j]

j = (j + 1) % texts.count
Expand Down