Skip to content

Commit 4c2f6a3

Browse files
committed
Initial commit.
1 parent 66597fd commit 4c2f6a3

File tree

7 files changed

+516
-11
lines changed

7 files changed

+516
-11
lines changed

ABPasscode.xcodeproj/project.pbxproj

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
295EDDC91F2B4E4C0093D79C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 295EDDC71F2B4E4C0093D79C /* Main.storyboard */; };
1313
295EDDCB1F2B4E4C0093D79C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 295EDDCA1F2B4E4C0093D79C /* Assets.xcassets */; };
1414
295EDDCE1F2B4E4C0093D79C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 295EDDCC1F2B4E4C0093D79C /* LaunchScreen.storyboard */; };
15+
295EDDDB1F2B4EC30093D79C /* ABButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 295EDDD71F2B4EC30093D79C /* ABButton.swift */; };
16+
295EDDDC1F2B4EC30093D79C /* PasscodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 295EDDD81F2B4EC30093D79C /* PasscodeViewController.swift */; };
17+
295EDDDD1F2B4EC30093D79C /* PasscodeViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 295EDDD91F2B4EC30093D79C /* PasscodeViewController.xib */; };
18+
295EDDDE1F2B4EC30093D79C /* String+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 295EDDDA1F2B4EC30093D79C /* String+Additions.swift */; };
1519
/* End PBXBuildFile section */
1620

1721
/* Begin PBXFileReference section */
@@ -22,6 +26,10 @@
2226
295EDDCA1F2B4E4C0093D79C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
2327
295EDDCD1F2B4E4C0093D79C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
2428
295EDDCF1F2B4E4C0093D79C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
29+
295EDDD71F2B4EC30093D79C /* ABButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ABButton.swift; sourceTree = "<group>"; };
30+
295EDDD81F2B4EC30093D79C /* PasscodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasscodeViewController.swift; sourceTree = "<group>"; };
31+
295EDDD91F2B4EC30093D79C /* PasscodeViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PasscodeViewController.xib; sourceTree = "<group>"; };
32+
295EDDDA1F2B4EC30093D79C /* String+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Additions.swift"; sourceTree = "<group>"; };
2533
/* End PBXFileReference section */
2634

2735
/* Begin PBXFrameworksBuildPhase section */
@@ -52,6 +60,26 @@
5260
sourceTree = "<group>";
5361
};
5462
295EDDC21F2B4E4C0093D79C /* ABPasscode */ = {
63+
isa = PBXGroup;
64+
children = (
65+
295EDDD61F2B4E610093D79C /* Example */,
66+
295EDDD51F2B4E5C0093D79C /* Source */,
67+
);
68+
path = ABPasscode;
69+
sourceTree = "<group>";
70+
};
71+
295EDDD51F2B4E5C0093D79C /* Source */ = {
72+
isa = PBXGroup;
73+
children = (
74+
295EDDD71F2B4EC30093D79C /* ABButton.swift */,
75+
295EDDD81F2B4EC30093D79C /* PasscodeViewController.swift */,
76+
295EDDD91F2B4EC30093D79C /* PasscodeViewController.xib */,
77+
295EDDDA1F2B4EC30093D79C /* String+Additions.swift */,
78+
);
79+
path = Source;
80+
sourceTree = "<group>";
81+
};
82+
295EDDD61F2B4E610093D79C /* Example */ = {
5583
isa = PBXGroup;
5684
children = (
5785
295EDDC31F2B4E4C0093D79C /* AppDelegate.swift */,
@@ -61,7 +89,7 @@
6189
295EDDCC1F2B4E4C0093D79C /* LaunchScreen.storyboard */,
6290
295EDDCF1F2B4E4C0093D79C /* Info.plist */,
6391
);
64-
path = ABPasscode;
92+
name = Example;
6593
sourceTree = "<group>";
6694
};
6795
/* End PBXGroup section */
@@ -123,6 +151,7 @@
123151
isa = PBXResourcesBuildPhase;
124152
buildActionMask = 2147483647;
125153
files = (
154+
295EDDDD1F2B4EC30093D79C /* PasscodeViewController.xib in Resources */,
126155
295EDDCE1F2B4E4C0093D79C /* LaunchScreen.storyboard in Resources */,
127156
295EDDCB1F2B4E4C0093D79C /* Assets.xcassets in Resources */,
128157
295EDDC91F2B4E4C0093D79C /* Main.storyboard in Resources */,
@@ -136,7 +165,10 @@
136165
isa = PBXSourcesBuildPhase;
137166
buildActionMask = 2147483647;
138167
files = (
168+
295EDDDC1F2B4EC30093D79C /* PasscodeViewController.swift in Sources */,
169+
295EDDDE1F2B4EC30093D79C /* String+Additions.swift in Sources */,
139170
295EDDC61F2B4E4C0093D79C /* ViewController.swift in Sources */,
171+
295EDDDB1F2B4EC30093D79C /* ABButton.swift in Sources */,
140172
295EDDC41F2B4E4C0093D79C /* AppDelegate.swift in Sources */,
141173
);
142174
runOnlyForDeploymentPostprocessing = 0;
@@ -299,6 +331,7 @@
299331
295EDDD41F2B4E4C0093D79C /* Release */,
300332
);
301333
defaultConfigurationIsVisible = 0;
334+
defaultConfigurationName = Release;
302335
};
303336
/* End XCConfigurationList section */
304337
};

ABPasscode/Base.lproj/Main.storyboard

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,74 @@
1-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11134" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="9ix-za-lIj">
3+
<device id="retina4_7" orientation="portrait">
4+
<adaptation id="fullscreen"/>
5+
</device>
36
<dependencies>
4-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11106"/>
7+
<deployment identifier="iOS"/>
8+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
59
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
610
</dependencies>
711
<scenes>
8-
<!--View Controller-->
12+
<!--Passcode Example-->
913
<scene sceneID="tne-QT-ifu">
1014
<objects>
11-
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
15+
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="ABPasscode" sceneMemberID="viewController">
1216
<layoutGuides>
1317
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
1418
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
1519
</layoutGuides>
1620
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
1721
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
1822
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
23+
<subviews>
24+
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6uK-iu-RVv">
25+
<rect key="frame" x="83.5" y="318.5" width="209" height="30"/>
26+
<state key="normal" title="Load Passcode view controller"/>
27+
<connections>
28+
<action selector="loadPasscodeViewController:" destination="BYZ-38-t0r" eventType="touchUpInside" id="gP6-Ln-U7D"/>
29+
</connections>
30+
</button>
31+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Entered Code:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="JSS-ha-6sp">
32+
<rect key="frame" x="132.5" y="247.5" width="110" height="21"/>
33+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
34+
<nil key="textColor"/>
35+
<nil key="highlightedColor"/>
36+
</label>
37+
</subviews>
1938
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
39+
<constraints>
40+
<constraint firstItem="6uK-iu-RVv" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="M8B-OW-YL8"/>
41+
<constraint firstItem="JSS-ha-6sp" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="NGN-dy-HjP"/>
42+
<constraint firstItem="6uK-iu-RVv" firstAttribute="centerY" secondItem="8bC-Xf-vdC" secondAttribute="centerY" id="tS2-kX-Ejc"/>
43+
<constraint firstItem="6uK-iu-RVv" firstAttribute="top" secondItem="JSS-ha-6sp" secondAttribute="bottom" constant="50" id="v12-te-5F5"/>
44+
</constraints>
2045
</view>
46+
<navigationItem key="navigationItem" title="Passcode Example" id="isD-Wh-vQT"/>
47+
<connections>
48+
<outlet property="lblPasscode" destination="JSS-ha-6sp" id="va7-dP-G4B"/>
49+
</connections>
2150
</viewController>
2251
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
2352
</objects>
53+
<point key="canvasLocation" x="942" y="777"/>
54+
</scene>
55+
<!--Navigation Controller-->
56+
<scene sceneID="HTx-um-GFX">
57+
<objects>
58+
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="9ix-za-lIj" sceneMemberID="viewController">
59+
<toolbarItems/>
60+
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Rzc-ma-V7a">
61+
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
62+
<autoresizingMask key="autoresizingMask"/>
63+
</navigationBar>
64+
<nil name="viewControllers"/>
65+
<connections>
66+
<segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="2a9-KE-EvD"/>
67+
</connections>
68+
</navigationController>
69+
<placeholder placeholderIdentifier="IBFirstResponder" id="ADu-zc-wnt" userLabel="First Responder" sceneMemberID="firstResponder"/>
70+
</objects>
71+
<point key="canvasLocation" x="116" y="776.76161919040487"/>
2472
</scene>
2573
</scenes>
2674
</document>

ABPasscode/Source/ABButton.swift

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//
2+
// ABButton.swift
3+
// Lango
4+
//
5+
// Created by Asif Bilal on 02/08/2016.
6+
// Copyright © 2016 Asif Bilal. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
12+
@IBDesignable class ABButton: UIButton {
13+
14+
override func awakeFromNib() {
15+
super.awakeFromNib()
16+
clipsToBounds = true
17+
}
18+
19+
override func layoutIfNeeded() {
20+
super.layoutIfNeeded()
21+
}
22+
23+
override var isSelected: Bool {
24+
didSet {
25+
backgroundColor = isSelected ? selectedBackgroundColor : normalBackgroundColor
26+
}
27+
}
28+
29+
@IBInspectable var selectedBackgroundColor : UIColor = UIColor.lightGray {
30+
didSet {
31+
backgroundColor = isSelected ? selectedBackgroundColor : normalBackgroundColor
32+
}
33+
}
34+
@IBInspectable var normalBackgroundColor : UIColor! = UIColor.white {
35+
didSet {
36+
backgroundColor = isSelected ? selectedBackgroundColor : normalBackgroundColor
37+
}
38+
}
39+
40+
@IBInspectable var cornerRadius: CGFloat = 0 {
41+
didSet {
42+
if !shouldCirlceButton {
43+
layer.cornerRadius = cornerRadius
44+
}
45+
}
46+
}
47+
48+
@IBInspectable var borderWidth: CGFloat = 0 {
49+
didSet {
50+
layer.borderWidth = borderWidth
51+
}
52+
}
53+
54+
@IBInspectable var borderColor: UIColor = UIColor.gray {
55+
didSet {
56+
layer.borderColor = borderColor.cgColor
57+
}
58+
}
59+
60+
@IBInspectable var shadowColor: UIColor = UIColor.white {
61+
didSet {
62+
layer.shadowColor = shadowColor.cgColor
63+
}
64+
}
65+
66+
@IBInspectable var shadowOffset: CGSize = CGSize.zero {
67+
didSet {
68+
layer.shadowOffset = shadowOffset
69+
layer.shadowOpacity = 1.0
70+
layer.shadowRadius = 1.0
71+
}
72+
}
73+
74+
@IBInspectable var textAlignment: Int = 0 {
75+
didSet {
76+
titleLabel?.textAlignment = NSTextAlignment(rawValue:textAlignment)!
77+
}
78+
}
79+
80+
@IBInspectable var shouldCirlceButton: Bool = false {
81+
didSet {
82+
if shouldCirlceButton == true {
83+
layer.cornerRadius = bounds.width/2
84+
} else {
85+
layer.cornerRadius = 0
86+
}
87+
}
88+
}
89+
90+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//
2+
// PasscodeViewController.swift
3+
// PasscodeViewController
4+
//
5+
// Created by Asif Bilal on 26/07/2017.
6+
// Copyright © 2017 Asif Bilal. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
@objc protocol PasscodeViewDelegate: class {
12+
func passcodeView(_ passcodeView:PasscodeViewController, didEnteredCode code: String)
13+
func passcodeView(_ passcodeView:PasscodeViewController, didTapResendButton resendButton:UIButton)
14+
@objc optional func passcodeView(_ passcodeView:PasscodeViewController, didTapNextButton nextButton:UIButton)
15+
}
16+
17+
class PasscodeViewController: UIViewController {
18+
19+
// MARK: - class properties
20+
let passcodeFieldBaseTag = 100
21+
22+
weak var delegate: PasscodeViewDelegate?
23+
24+
// MARK: - IBOutlets
25+
26+
@IBOutlet fileprivate weak var passcodeView: UIView!
27+
@IBOutlet fileprivate weak var dummyTextField: UITextField!
28+
29+
// MARK: - life cycle
30+
31+
override func viewWillAppear(_ animated: Bool) {
32+
super.viewWillAppear(animated)
33+
viewConfigurations()
34+
}
35+
36+
override func viewDidLoad() {
37+
super.viewDidLoad()
38+
}
39+
40+
override func didReceiveMemoryWarning() {
41+
super.didReceiveMemoryWarning()
42+
// Dispose of any resources that can be recreated.
43+
}
44+
45+
// MARK: - IBActions
46+
47+
@IBAction func editingChanged(_ sender: UITextField) {
48+
49+
var currentTextLength = 0
50+
if let textFieldText = sender.text {
51+
currentTextLength = textFieldText.length
52+
}
53+
54+
for i in 0 ..< currentTextLength {
55+
let textField = passcodeView.viewWithTag(passcodeFieldBaseTag + i) as! UITextField
56+
57+
let startIndex = sender.text!.characters.index(sender.text!.startIndex, offsetBy: i)
58+
let endIndex = sender.text!.characters.index(sender.text!.startIndex, offsetBy: i+1)
59+
let range = startIndex..<endIndex
60+
textField.text = sender.text?.substring(with: range)
61+
}
62+
63+
for i in sender.text!.length ..< 4 {
64+
let textField = passcodeView.viewWithTag(passcodeFieldBaseTag + i) as! UITextField
65+
textField.text = ""
66+
}
67+
68+
let code = sender.text
69+
if code?.length == 4 {
70+
delegate?.passcodeView(self, didEnteredCode: code!)
71+
}
72+
73+
74+
}
75+
76+
@IBAction func resendCodeTouchUpInside(_ sender: AnyObject) {
77+
78+
}
79+
80+
@IBAction func nextTouchUpInside(_ sender: AnyObject) {
81+
}
82+
83+
// MARK: - private functions
84+
85+
fileprivate func viewConfigurations() {
86+
87+
edgesForExtendedLayout = []
88+
dummyTextField.becomeFirstResponder()
89+
}
90+
91+
fileprivate func resetPassCodeFields() {
92+
93+
dummyTextField.text = ""
94+
for i in 0 ..< 4 {
95+
let textField = passcodeView.viewWithTag(passcodeFieldBaseTag + i) as! UITextField
96+
textField.text = ""
97+
}
98+
99+
}
100+
101+
}
102+
103+
extension PasscodeViewController: UITextFieldDelegate {
104+
105+
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
106+
107+
var oldLength = 0
108+
109+
if let textFieldText = textField.text {
110+
oldLength = textFieldText.length
111+
}
112+
113+
let replacementLength = string.length
114+
let rangeLength = range.length
115+
let newLength = oldLength - rangeLength + replacementLength
116+
let returnKey = string.range(of: "\n") != nil
117+
return newLength <= 4 || returnKey
118+
119+
}
120+
121+
122+
}

0 commit comments

Comments
 (0)