diff --git a/.DS_Store b/.DS_Store index e7c1f61..a381b3e 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Demo/Assets.xcassets/Contents.json b/Demo/Assets.xcassets/Contents.json index da4a164..73c0059 100644 --- a/Demo/Assets.xcassets/Contents.json +++ b/Demo/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git "a/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/Contents.json" "b/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/Contents.json" new file mode 100644 index 0000000..cec24c6 --- /dev/null +++ "b/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/Contents.json" @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "登录-底图 2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "登录-底图 2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git "a/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/\347\231\273\345\275\225-\345\272\225\345\233\276 2@2x.png" "b/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/\347\231\273\345\275\225-\345\272\225\345\233\276 2@2x.png" new file mode 100644 index 0000000..c1722d2 Binary files /dev/null and "b/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/\347\231\273\345\275\225-\345\272\225\345\233\276 2@2x.png" differ diff --git "a/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/\347\231\273\345\275\225-\345\272\225\345\233\276 2@3x.png" "b/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/\347\231\273\345\275\225-\345\272\225\345\233\276 2@3x.png" new file mode 100644 index 0000000..67d6bc4 Binary files /dev/null and "b/Demo/Assets.xcassets/\347\231\273\345\275\225-\345\272\225\345\233\276 2.imageset/\347\231\273\345\275\225-\345\272\225\345\233\276 2@3x.png" differ diff --git a/Demo/Base.lproj/Main.storyboard b/Demo/Base.lproj/Main.storyboard index f1bcf38..2beaac3 100644 --- a/Demo/Base.lproj/Main.storyboard +++ b/Demo/Base.lproj/Main.storyboard @@ -1,7 +1,9 @@ - + + - + + @@ -9,16 +11,31 @@ - + - + - + + + + + + + + + + + + + + + + diff --git a/Demo/ViewController.swift b/Demo/ViewController.swift index 1b68c73..f1383ac 100644 --- a/Demo/ViewController.swift +++ b/Demo/ViewController.swift @@ -14,7 +14,7 @@ class ViewController: UIViewController { // default item view let pinCodeInputView: PinCodeInputView = .init( digit: 6, - itemSpacing: 8, + itemSpacing: 10, itemFactory: { return ItemView() }, @@ -65,22 +65,24 @@ class ViewController: UIViewController { titleLabel.font = UIFont.systemFont(ofSize: 24, weight: .bold) titleLabel.textColor = UIColor.lightText titleLabel.frame = CGRect(x: 0, y: 0, width: view.bounds.width - 56, height: 60) - titleLabel.center = CGPoint(x: view.center.x, y: view.center.y - 94) + titleLabel.center = CGPoint(x: view.center.x, y: view.center.y - 124) pinCodeInputView.frame = CGRect(x: 0, y: 0, width: view.bounds.width - 56, height: 80) - pinCodeInputView.center = view.center + pinCodeInputView.center = CGPoint(x: view.center.x, y: view.center.y - 30) pinCodeInputView.set(changeTextHandler: { text in print(text) }) pinCodeInputView.set( appearance: .init( - itemSize: CGSize(width: 44, height: 68), - font: .systemFont(ofSize: 28, weight: .bold), - textColor: .white, - backgroundColor: UIColor.white.withAlphaComponent(0.3), + itemSize: CGSize(width: 48, height: 48), + font: .systemFont(ofSize: 20, weight: .bold), + textColor: .black, + backgroundColor: UIColor.white.withAlphaComponent(0.8), + highlightBackgroundColor: UIColor(red: 186/255.0, green: 212/255.0, blue: 255/255.0, alpha: 0.8), cursorColor: UIColor(red: 69/255, green: 108/255, blue: 1, alpha: 1), - cornerRadius: 8, - borderColor: UIColor.red + cornerRadius: 4, + highlightBorderColor: UIColor(red: 38/255.0, green: 86/255.0, blue: 235/255.0, alpha: 1), + borderColor:.white ) ) diff --git a/PinCodeInputView.podspec b/PinCodeInputView.podspec index e2c8e1a..a83a83c 100644 --- a/PinCodeInputView.podspec +++ b/PinCodeInputView.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.name = "PinCodeInputView" - s.version = "1.0.0" + s.version = "1.1.1" s.summary = "TextView for entering pin code. " s.description = <<-DESC diff --git a/PinCodeInputView.xcodeproj/project.pbxproj b/PinCodeInputView.xcodeproj/project.pbxproj index 40b9c6b..217601d 100644 --- a/PinCodeInputView.xcodeproj/project.pbxproj +++ b/PinCodeInputView.xcodeproj/project.pbxproj @@ -502,7 +502,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 64T4PJ8WCZ; + DEVELOPMENT_TEAM = 2286X5X7D9; INFOPLIST_FILE = Demo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -521,7 +521,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 64T4PJ8WCZ; + DEVELOPMENT_TEAM = 2286X5X7D9; INFOPLIST_FILE = Demo/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/PinCodeInputView/ItemAppearance.swift b/PinCodeInputView/ItemAppearance.swift index 28d9c41..5fd7d23 100644 --- a/PinCodeInputView/ItemAppearance.swift +++ b/PinCodeInputView/ItemAppearance.swift @@ -14,25 +14,32 @@ public struct ItemAppearance { public let font: UIFont public let textColor: UIColor public let backgroundColor: UIColor + public let highlightBackgroundColor: UIColor public let cursorColor: UIColor public let cornerRadius: CGFloat public let borderColor: UIColor + public let highlightBorderColor: UIColor + public init( itemSize: CGSize, font: UIFont, textColor: UIColor, backgroundColor: UIColor, + highlightBackgroundColor: UIColor, cursorColor: UIColor, cornerRadius: CGFloat, + highlightBorderColor: UIColor = UIColor.clear, borderColor: UIColor = UIColor.clear) { self.itemSize = itemSize self.font = font self.textColor = textColor self.backgroundColor = backgroundColor + self.highlightBackgroundColor = highlightBackgroundColor self.cursorColor = cursorColor self.cornerRadius = cornerRadius self.borderColor = borderColor + self.highlightBorderColor = highlightBorderColor } } diff --git a/PinCodeInputView/ItemView.swift b/PinCodeInputView/ItemView.swift index 21f5968..bfae4ba 100644 --- a/PinCodeInputView/ItemView.swift +++ b/PinCodeInputView/ItemView.swift @@ -27,8 +27,12 @@ public class ItemView: UIView, ItemType { didSet { cursor.isHidden = isHiddenCursor if (isHiddenCursor) { - self.layer.borderWidth = 0 + self.backgroundColor = _appearance?.backgroundColor + self.layer.borderColor = _appearance?.borderColor.cgColor + self.layer.borderWidth = 1 } else { + self.backgroundColor = _appearance?.highlightBackgroundColor + self.layer.borderColor = _appearance?.highlightBorderColor.cgColor self.layer.borderWidth = 1 } } @@ -50,27 +54,36 @@ public class ItemView: UIView, ItemType { label.isUserInteractionEnabled = false cursor.isHidden = true - - UIView.animateKeyframes( - withDuration: 1.6, - delay: 0.8, - options: [.repeat], - animations: { - UIView.addKeyframe( - withRelativeStartTime: 0, - relativeDuration: 0.2, - animations: { - self.cursor.alpha = 0 - }) - UIView.addKeyframe( - withRelativeStartTime: 0.8, - relativeDuration: 0.2, - animations: { - self.cursor.alpha = 1 - }) - }, - completion: nil - ) + NotificationCenter.default.addObserver(self, selector: #selector(becomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(enterBack), name: UIApplication.didEnterBackgroundNotification, object: nil) + becomeActive() + + } + + /// 闪烁动画 + fileprivate var opacityAnimation: CABasicAnimation = { + let opacityAnimation = CABasicAnimation.init(keyPath: "opacity") + opacityAnimation.fromValue = 1.0 + opacityAnimation.toValue = 0.0 + opacityAnimation.duration = 0.9 + opacityAnimation.repeatCount = HUGE + opacityAnimation.isRemovedOnCompletion = true + opacityAnimation.fillMode = .forwards + opacityAnimation.timingFunction = CAMediaTimingFunction.init(name: .linear) + return opacityAnimation + }() + + + /// 去后台 + @objc fileprivate func enterBack() { + // 移除动画 + cursor.layer.removeAnimation(forKey: "kOpacityAnimation") + } + + /// 回前台 + @objc fileprivate func becomeActive() { + // 重新添加动画 + cursor.layer.add(opacityAnimation, forKey: "kOpacityAnimation") } required init?(coder aDecoder: NSCoder) { @@ -93,7 +106,10 @@ public class ItemView: UIView, ItemType { ) } + private var _appearance: ItemAppearance? + public func set(appearance: ItemAppearance) { + _appearance = appearance bounds.size = appearance.itemSize label.font = appearance.font label.textColor = appearance.textColor diff --git a/PinCodeInputView/PinCodeInputView.swift b/PinCodeInputView/PinCodeInputView.swift index 4f13cf3..dc32d3c 100644 --- a/PinCodeInputView/PinCodeInputView.swift +++ b/PinCodeInputView/PinCodeInputView.swift @@ -26,6 +26,8 @@ public class PinCodeInputView: UIControl, UITextInputTrait return text.isEmpty } + public var canPaste: Bool = true + public var isFilled: Bool { return text.count == digit } @@ -33,6 +35,11 @@ public class PinCodeInputView: UIControl, UITextInputTrait public var hasText: Bool { return !(text.isEmpty) } + + public var currentFocusIndex: Int { + if isFilled { return 0 } + return text.count + } override public var intrinsicContentSize: CGSize { return stackView.bounds.size @@ -86,6 +93,42 @@ public class PinCodeInputView: UIControl, UITextInputTrait stackView.spacing = itemSpacing stackView.axis = .horizontal stackView.distribution = .fillEqually + setupGestures() + } + + + private func setupGestures() { + let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:))) + self.addGestureRecognizer(longPressGesture) + } + + // MARK: - Long Press Handler + + @objc private func handleLongPress(_ gesture: UILongPressGestureRecognizer) { + if gesture.state == .began && canPaste { + becomeFirstResponder() + // 显示粘贴菜单 + + let menu = UIMenuController.shared + menu.menuItems = [UIMenuItem(title: "粘贴", action: #selector(pasteText))] + let focusView = self.items[currentFocusIndex] + let targetFrame = focusView.convert(focusView.bounds, to: self) + menu.setTargetRect(targetFrame, in: self) + menu.setMenuVisible(true, animated: true) + } + } + + @objc private func pasteText() { + if let pasteString = UIPasteboard.general.string { + set(text: pasteString) + } + } + + public override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { + if action == #selector(pasteText) { + return UIPasteboard.general.string != nil + } + return false } required init?(coder aDecoder: NSCoder) { @@ -121,10 +164,14 @@ public class PinCodeInputView: UIControl, UITextInputTrait self.changeTextHandler = changeTextHandler } + public func clear() { + self.text = "" + } + public func set(appearance: ItemAppearance) { self.appearance = appearance if autoResizes { - self.appearance = ItemAppearance(itemSize: CGSize(width: (self.bounds.width - (self.itemSpacing * CGFloat(self.digit))) / CGFloat(self.digit), height: appearance.itemSize.height), font: appearance.font, textColor: appearance.textColor, backgroundColor: appearance.backgroundColor, cursorColor: appearance.cursorColor, cornerRadius: appearance.cornerRadius, borderColor: appearance.borderColor) + self.appearance = ItemAppearance(itemSize: CGSize(width: (self.bounds.width - (self.itemSpacing * CGFloat(self.digit))) / CGFloat(self.digit), height: appearance.itemSize.height), font: appearance.font, textColor: appearance.textColor, backgroundColor: appearance.backgroundColor, highlightBackgroundColor: appearance.highlightBackgroundColor, cursorColor: appearance.cursorColor, cornerRadius: appearance.cornerRadius, highlightBorderColor: appearance.highlightBorderColor, borderColor: appearance.borderColor) } items.forEach { $0.itemView.set(appearance: appearance) } }