├── logo.png
├── style.png
├── SYKeyboard.gif
├── Snip20150129_1.png
├── KeyboardTextFieldDemo
├── KeyboardTextFieldDemo.xcodeproj
│ ├── project.xcworkspace
│ │ ├── xcuserdata
│ │ │ └── yushuyi.xcuserdatad
│ │ │ │ └── UserInterfaceState.xcuserstate
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ └── SYKeyboardTextFieldDemo.xccheckout
│ ├── xcuserdata
│ │ └── yushuyi.xcuserdatad
│ │ │ ├── xcschemes
│ │ │ ├── xcschememanagement.plist
│ │ │ └── KeyboardTextFieldDemo.xcscheme
│ │ │ └── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ └── project.pbxproj
└── KeyboardTextFieldDemo
│ ├── Images.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Info.plist
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.xib
│ └── ViewController.swift
├── README.md
└── KeyboardTextField
└── KeyboardTextField.swift
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yushuyi/KeyboardTextField/HEAD/logo.png
--------------------------------------------------------------------------------
/style.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yushuyi/KeyboardTextField/HEAD/style.png
--------------------------------------------------------------------------------
/SYKeyboard.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yushuyi/KeyboardTextField/HEAD/SYKeyboard.gif
--------------------------------------------------------------------------------
/Snip20150129_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yushuyi/KeyboardTextField/HEAD/Snip20150129_1.png
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/project.xcworkspace/xcuserdata/yushuyi.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yushuyi/KeyboardTextField/HEAD/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/project.xcworkspace/xcuserdata/yushuyi.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/xcuserdata/yushuyi.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | KeyboardTextFieldDemo.xcscheme
8 |
9 | orderHint
10 | 2
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 22918F5A1A79C48200547672
16 |
17 | primary
18 |
19 |
20 | 22918F6F1A79C48300547672
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | * [System requirements](#system-requirements)
2 |
3 |
4 |
5 |
6 |
7 | KeyboardTextField is a lightweight, simple, non-invasive keyboard accompanying input box! Write in Swift!
8 |
9 |
10 |
11 | ## Requirements
12 |
13 | - Swift 4
14 | - iOS 8.0 or later
15 |
16 |
17 | ## Installation
18 | - Drag the file to your project
19 |
20 | ## Usage
21 | keyboardTextField = KeyboardTextField(point: CGPoint(x: 0, y: 0), width: self.view.bounds.size.width)
22 | keyboardTextField.delegate = self
23 | keyboardTextField.isLeftButtonHidden = false
24 | keyboardTextField.isRightButtonHidden = false
25 | keyboardTextField.autoresizingMask = [UIViewAutoresizing.flexibleWidth , UIViewAutoresizing.flexibleTopMargin]
26 | self.view.addSubview(keyboardTextField)
27 | keyboardTextField.toFullyBottom()
28 | ## How to custom UI Style ?
29 | //UI
30 | lazy var keyboardView = UIView()
31 | lazy var textView : KeyboardTextView = KeyboardTextView()
32 | lazy var placeholderLabel = UILabel()
33 | lazy var textViewBackground = UIImageView()
34 | lazy var leftButton = UIButton()
35 | lazy var rightButton = UIButton()
36 |
37 |
38 |
39 | ## Author
40 |
41 | [@余书懿](http://weibo.com/ysy441088327)
42 |
43 | ## License
44 |
45 | KeyboardTextField is available under the MIT license.
46 | System requirements
47 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/project.xcworkspace/xcshareddata/SYKeyboardTextFieldDemo.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 564EA73C-149C-4C7E-833B-6F7B8284793C
9 | IDESourceControlProjectName
10 | SYKeyboardTextFieldDemo
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 511F8F817E53F0962706C08958EE2371E64696D1
14 | https://github.com/441088327/SYKeyboardTextField.git
15 |
16 | IDESourceControlProjectPath
17 | SYKeyboardTextFieldDemo/SYKeyboardTextFieldDemo.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 511F8F817E53F0962706C08958EE2371E64696D1
21 | ../../..
22 |
23 | IDESourceControlProjectURL
24 | https://github.com/441088327/SYKeyboardTextField.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 511F8F817E53F0962706C08958EE2371E64696D1
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 511F8F817E53F0962706C08958EE2371E64696D1
36 | IDESourceControlWCCName
37 | SYKeyboardTextField
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // KeyboardTextFieldDemo
4 | //
5 | // Created by yushuyi on 15/1/29.
6 | // Copyright (c) 2015年 yushuyi. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo/Base.lproj/LaunchScreen.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/xcuserdata/yushuyi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
20 |
21 |
22 |
24 |
36 |
37 |
38 |
40 |
52 |
53 |
54 |
56 |
68 |
69 |
70 |
72 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // KeyboardTextFieldDemo
4 | //
5 | // Created by yushuyi on 15/1/29.
6 | // Copyright (c) 2015年 yushuyi. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ViewController: UIViewController {
12 |
13 | var keyboardTextField : KeyboardTextField!
14 |
15 |
16 | override func loadView() {
17 | super.loadView()
18 | keyboardTextField = DNKeyboardTextField(point: CGPoint(x: 0, y: 0), width: self.view.bounds.size.width)
19 | keyboardTextField.delegate = self
20 | keyboardTextField.isLeftButtonHidden = true
21 | keyboardTextField.isRightButtonHidden = false
22 | keyboardTextField.autoresizingMask = [UIViewAutoresizing.flexibleWidth , UIViewAutoresizing.flexibleTopMargin]
23 | self.view.addSubview(keyboardTextField)
24 | keyboardTextField.toFullyBottom()
25 |
26 | let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
27 | view.backgroundColor = UIColor.red
28 | keyboardTextField.addAttachmentView(view)
29 | }
30 |
31 |
32 | override func viewDidLoad() {
33 | super.viewDidLoad()
34 |
35 | }
36 |
37 | override func didReceiveMemoryWarning() {
38 | super.didReceiveMemoryWarning()
39 | // Dispose of any resources that can be recreated.
40 | }
41 | }
42 |
43 | //MARK: KeyboardTextFieldDelegate
44 | extension ViewController : KeyboardTextFieldDelegate {
45 | func keyboardTextFieldPressReturnButton(_ keyboardTextField: KeyboardTextField) {
46 | UIAlertView(title: "", message: "Action", delegate: nil, cancelButtonTitle: "OK").show()
47 | }
48 | }
49 |
50 |
51 | class DNKeyboardTextField : KeyboardTextField {
52 |
53 | override init(frame : CGRect) {
54 | super.init(frame : frame)
55 | self.clearTestColor()
56 |
57 | //Right Button
58 | self.rightButton.showsTouchWhenHighlighted = true
59 | self.rightButton.backgroundColor = UIColor(rgb: (252,49,89))
60 | self.rightButton.clipsToBounds = true
61 | self.rightButton.layer.cornerRadius = 18
62 | self.rightButton.setTitle("^0^", for: .normal)
63 | self.rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 16)
64 |
65 | //TextView
66 | self.textViewBackground.layer.borderColor = UIColor(rgb: (191,191,191)).cgColor
67 | self.textViewBackground.backgroundColor = UIColor.white
68 | self.textViewBackground.layer.cornerRadius = 18
69 | self.textViewBackground.layer.masksToBounds = true
70 | self.keyboardView.backgroundColor = UIColor(rgb: (238,238,238))
71 | self.placeholderLabel.textAlignment = .center
72 | self.placeholderLabel.text = "^_^"
73 | self.placeholderLabel.textColor = UIColor(rgb: (153,153,153))
74 |
75 | self.leftRightDistance = 15.0
76 | self.middleDistance = 5.0
77 | self.buttonMinWidth = 60
78 | }
79 |
80 | required init?(coder aDecoder: NSCoder) {
81 | super.init(coder: aDecoder)
82 | }
83 |
84 | }
85 |
86 | extension UIView {
87 | func toFullyBottom() {
88 | self.bottom = superview!.bounds.size.height
89 | self.autoresizingMask = [UIViewAutoresizing.flexibleTopMargin, UIViewAutoresizing.flexibleWidth]
90 | }
91 |
92 | public var bottom: CGFloat{
93 | get {
94 | return self.frame.origin.y + self.frame.size.height
95 | }
96 | set {
97 | var frame = self.frame;
98 | frame.origin.y = newValue - frame.size.height;
99 | self.frame = frame;
100 | }
101 | }
102 | }
103 |
104 | extension UIColor {
105 |
106 | convenience init(rgb: (r: CGFloat, g: CGFloat, b: CGFloat)) {
107 | self.init(red: rgb.r/255, green: rgb.g/255, blue: rgb.b/255, alpha: 1)
108 | }
109 | convenience init(rgba: (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat)) {
110 | self.init(red: rgba.r/255, green: rgba.g/255, blue: rgba.b/255, alpha: rgba.a)
111 | }
112 | }
113 |
114 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/xcuserdata/yushuyi.xcuserdatad/xcschemes/KeyboardTextFieldDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
48 |
54 |
55 |
56 |
57 |
58 |
64 |
65 |
66 |
67 |
68 |
69 |
80 |
82 |
88 |
89 |
90 |
91 |
92 |
93 |
99 |
101 |
107 |
108 |
109 |
110 |
112 |
113 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/KeyboardTextFieldDemo/KeyboardTextFieldDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2277E8512064A3080042AB77 /* KeyboardTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2277E8502064A3070042AB77 /* KeyboardTextField.swift */; };
11 | 22918F611A79C48200547672 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22918F601A79C48200547672 /* AppDelegate.swift */; };
12 | 22918F631A79C48200547672 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22918F621A79C48200547672 /* ViewController.swift */; };
13 | 22918F661A79C48200547672 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 22918F641A79C48200547672 /* Main.storyboard */; };
14 | 22918F681A79C48200547672 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 22918F671A79C48200547672 /* Images.xcassets */; };
15 | 22918F6B1A79C48200547672 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 22918F691A79C48200547672 /* LaunchScreen.xib */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 2277E8502064A3070042AB77 /* KeyboardTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardTextField.swift; sourceTree = ""; };
20 | 22918F5B1A79C48200547672 /* KeyboardTextFieldDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeyboardTextFieldDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | 22918F5F1A79C48200547672 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
22 | 22918F601A79C48200547672 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
23 | 22918F621A79C48200547672 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
24 | 22918F651A79C48200547672 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | 22918F671A79C48200547672 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
26 | 22918F6A1A79C48200547672 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
27 | /* End PBXFileReference section */
28 |
29 | /* Begin PBXFrameworksBuildPhase section */
30 | 22918F581A79C48200547672 /* Frameworks */ = {
31 | isa = PBXFrameworksBuildPhase;
32 | buildActionMask = 2147483647;
33 | files = (
34 | );
35 | runOnlyForDeploymentPostprocessing = 0;
36 | };
37 | /* End PBXFrameworksBuildPhase section */
38 |
39 | /* Begin PBXGroup section */
40 | 22918F521A79C48200547672 = {
41 | isa = PBXGroup;
42 | children = (
43 | 22918F801A79C7EA00547672 /* KeyboardTextField */,
44 | 22918F5D1A79C48200547672 /* KeyboardTextFieldDemo */,
45 | 22918F5C1A79C48200547672 /* Products */,
46 | );
47 | sourceTree = "";
48 | };
49 | 22918F5C1A79C48200547672 /* Products */ = {
50 | isa = PBXGroup;
51 | children = (
52 | 22918F5B1A79C48200547672 /* KeyboardTextFieldDemo.app */,
53 | );
54 | name = Products;
55 | sourceTree = "";
56 | };
57 | 22918F5D1A79C48200547672 /* KeyboardTextFieldDemo */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 22918F601A79C48200547672 /* AppDelegate.swift */,
61 | 22918F621A79C48200547672 /* ViewController.swift */,
62 | 22918F641A79C48200547672 /* Main.storyboard */,
63 | 22918F671A79C48200547672 /* Images.xcassets */,
64 | 22918F691A79C48200547672 /* LaunchScreen.xib */,
65 | 22918F5E1A79C48200547672 /* Supporting Files */,
66 | );
67 | path = KeyboardTextFieldDemo;
68 | sourceTree = "";
69 | };
70 | 22918F5E1A79C48200547672 /* Supporting Files */ = {
71 | isa = PBXGroup;
72 | children = (
73 | 22918F5F1A79C48200547672 /* Info.plist */,
74 | );
75 | name = "Supporting Files";
76 | sourceTree = "";
77 | };
78 | 22918F801A79C7EA00547672 /* KeyboardTextField */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 2277E8502064A3070042AB77 /* KeyboardTextField.swift */,
82 | );
83 | name = KeyboardTextField;
84 | path = ../KeyboardTextField;
85 | sourceTree = "";
86 | };
87 | /* End PBXGroup section */
88 |
89 | /* Begin PBXNativeTarget section */
90 | 22918F5A1A79C48200547672 /* KeyboardTextFieldDemo */ = {
91 | isa = PBXNativeTarget;
92 | buildConfigurationList = 22918F7A1A79C48300547672 /* Build configuration list for PBXNativeTarget "KeyboardTextFieldDemo" */;
93 | buildPhases = (
94 | 22918F571A79C48200547672 /* Sources */,
95 | 22918F581A79C48200547672 /* Frameworks */,
96 | 22918F591A79C48200547672 /* Resources */,
97 | );
98 | buildRules = (
99 | );
100 | dependencies = (
101 | );
102 | name = KeyboardTextFieldDemo;
103 | productName = SYKeyboardTextFieldDemo;
104 | productReference = 22918F5B1A79C48200547672 /* KeyboardTextFieldDemo.app */;
105 | productType = "com.apple.product-type.application";
106 | };
107 | /* End PBXNativeTarget section */
108 |
109 | /* Begin PBXProject section */
110 | 22918F531A79C48200547672 /* Project object */ = {
111 | isa = PBXProject;
112 | attributes = {
113 | LastSwiftUpdateCheck = 0700;
114 | LastUpgradeCheck = 0800;
115 | ORGANIZATIONNAME = yushuyi;
116 | TargetAttributes = {
117 | 22918F5A1A79C48200547672 = {
118 | CreatedOnToolsVersion = 6.1.1;
119 | DevelopmentTeam = EWEN586K6F;
120 | LastSwiftMigration = 0800;
121 | };
122 | };
123 | };
124 | buildConfigurationList = 22918F561A79C48200547672 /* Build configuration list for PBXProject "KeyboardTextFieldDemo" */;
125 | compatibilityVersion = "Xcode 3.2";
126 | developmentRegion = English;
127 | hasScannedForEncodings = 0;
128 | knownRegions = (
129 | en,
130 | Base,
131 | );
132 | mainGroup = 22918F521A79C48200547672;
133 | productRefGroup = 22918F5C1A79C48200547672 /* Products */;
134 | projectDirPath = "";
135 | projectRoot = "";
136 | targets = (
137 | 22918F5A1A79C48200547672 /* KeyboardTextFieldDemo */,
138 | );
139 | };
140 | /* End PBXProject section */
141 |
142 | /* Begin PBXResourcesBuildPhase section */
143 | 22918F591A79C48200547672 /* Resources */ = {
144 | isa = PBXResourcesBuildPhase;
145 | buildActionMask = 2147483647;
146 | files = (
147 | 22918F661A79C48200547672 /* Main.storyboard in Resources */,
148 | 22918F6B1A79C48200547672 /* LaunchScreen.xib in Resources */,
149 | 22918F681A79C48200547672 /* Images.xcassets in Resources */,
150 | );
151 | runOnlyForDeploymentPostprocessing = 0;
152 | };
153 | /* End PBXResourcesBuildPhase section */
154 |
155 | /* Begin PBXSourcesBuildPhase section */
156 | 22918F571A79C48200547672 /* Sources */ = {
157 | isa = PBXSourcesBuildPhase;
158 | buildActionMask = 2147483647;
159 | files = (
160 | 2277E8512064A3080042AB77 /* KeyboardTextField.swift in Sources */,
161 | 22918F631A79C48200547672 /* ViewController.swift in Sources */,
162 | 22918F611A79C48200547672 /* AppDelegate.swift in Sources */,
163 | );
164 | runOnlyForDeploymentPostprocessing = 0;
165 | };
166 | /* End PBXSourcesBuildPhase section */
167 |
168 | /* Begin PBXVariantGroup section */
169 | 22918F641A79C48200547672 /* Main.storyboard */ = {
170 | isa = PBXVariantGroup;
171 | children = (
172 | 22918F651A79C48200547672 /* Base */,
173 | );
174 | name = Main.storyboard;
175 | sourceTree = "";
176 | };
177 | 22918F691A79C48200547672 /* LaunchScreen.xib */ = {
178 | isa = PBXVariantGroup;
179 | children = (
180 | 22918F6A1A79C48200547672 /* Base */,
181 | );
182 | name = LaunchScreen.xib;
183 | sourceTree = "";
184 | };
185 | /* End PBXVariantGroup section */
186 |
187 | /* Begin XCBuildConfiguration section */
188 | 22918F781A79C48300547672 /* Debug */ = {
189 | isa = XCBuildConfiguration;
190 | buildSettings = {
191 | ALWAYS_SEARCH_USER_PATHS = NO;
192 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
193 | CLANG_CXX_LIBRARY = "libc++";
194 | CLANG_ENABLE_MODULES = YES;
195 | CLANG_ENABLE_OBJC_ARC = YES;
196 | CLANG_WARN_BOOL_CONVERSION = YES;
197 | CLANG_WARN_CONSTANT_CONVERSION = YES;
198 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
199 | CLANG_WARN_EMPTY_BODY = YES;
200 | CLANG_WARN_ENUM_CONVERSION = YES;
201 | CLANG_WARN_INFINITE_RECURSION = YES;
202 | CLANG_WARN_INT_CONVERSION = YES;
203 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
204 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
205 | CLANG_WARN_UNREACHABLE_CODE = YES;
206 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
207 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
208 | COPY_PHASE_STRIP = NO;
209 | ENABLE_STRICT_OBJC_MSGSEND = YES;
210 | ENABLE_TESTABILITY = YES;
211 | GCC_C_LANGUAGE_STANDARD = gnu99;
212 | GCC_DYNAMIC_NO_PIC = NO;
213 | GCC_NO_COMMON_BLOCKS = YES;
214 | GCC_OPTIMIZATION_LEVEL = 0;
215 | GCC_PREPROCESSOR_DEFINITIONS = (
216 | "DEBUG=1",
217 | "$(inherited)",
218 | );
219 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
220 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
221 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
222 | GCC_WARN_UNDECLARED_SELECTOR = YES;
223 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
224 | GCC_WARN_UNUSED_FUNCTION = YES;
225 | GCC_WARN_UNUSED_VARIABLE = YES;
226 | IPHONEOS_DEPLOYMENT_TARGET = 8.1;
227 | MTL_ENABLE_DEBUG_INFO = YES;
228 | ONLY_ACTIVE_ARCH = YES;
229 | SDKROOT = iphoneos;
230 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
231 | };
232 | name = Debug;
233 | };
234 | 22918F791A79C48300547672 /* Release */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
239 | CLANG_CXX_LIBRARY = "libc++";
240 | CLANG_ENABLE_MODULES = YES;
241 | CLANG_ENABLE_OBJC_ARC = YES;
242 | CLANG_WARN_BOOL_CONVERSION = YES;
243 | CLANG_WARN_CONSTANT_CONVERSION = YES;
244 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
245 | CLANG_WARN_EMPTY_BODY = YES;
246 | CLANG_WARN_ENUM_CONVERSION = YES;
247 | CLANG_WARN_INFINITE_RECURSION = YES;
248 | CLANG_WARN_INT_CONVERSION = YES;
249 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
250 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
251 | CLANG_WARN_UNREACHABLE_CODE = YES;
252 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
253 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
254 | COPY_PHASE_STRIP = YES;
255 | ENABLE_NS_ASSERTIONS = NO;
256 | ENABLE_STRICT_OBJC_MSGSEND = YES;
257 | GCC_C_LANGUAGE_STANDARD = gnu99;
258 | GCC_NO_COMMON_BLOCKS = YES;
259 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
260 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
261 | GCC_WARN_UNDECLARED_SELECTOR = YES;
262 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
263 | GCC_WARN_UNUSED_FUNCTION = YES;
264 | GCC_WARN_UNUSED_VARIABLE = YES;
265 | IPHONEOS_DEPLOYMENT_TARGET = 8.1;
266 | MTL_ENABLE_DEBUG_INFO = NO;
267 | SDKROOT = iphoneos;
268 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
269 | VALIDATE_PRODUCT = YES;
270 | };
271 | name = Release;
272 | };
273 | 22918F7B1A79C48300547672 /* Debug */ = {
274 | isa = XCBuildConfiguration;
275 | buildSettings = {
276 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
277 | DEVELOPMENT_TEAM = EWEN586K6F;
278 | INFOPLIST_FILE = KeyboardTextFieldDemo/Info.plist;
279 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
280 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
281 | PRODUCT_BUNDLE_IDENTIFIER = "com.yushuyi.$(PRODUCT_NAME:rfc1034identifier)";
282 | PRODUCT_NAME = "$(TARGET_NAME)";
283 | SWIFT_VERSION = 4.0;
284 | };
285 | name = Debug;
286 | };
287 | 22918F7C1A79C48300547672 /* Release */ = {
288 | isa = XCBuildConfiguration;
289 | buildSettings = {
290 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
291 | DEVELOPMENT_TEAM = EWEN586K6F;
292 | INFOPLIST_FILE = KeyboardTextFieldDemo/Info.plist;
293 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
294 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
295 | PRODUCT_BUNDLE_IDENTIFIER = "com.yushuyi.$(PRODUCT_NAME:rfc1034identifier)";
296 | PRODUCT_NAME = "$(TARGET_NAME)";
297 | SWIFT_VERSION = 4.0;
298 | };
299 | name = Release;
300 | };
301 | /* End XCBuildConfiguration section */
302 |
303 | /* Begin XCConfigurationList section */
304 | 22918F561A79C48200547672 /* Build configuration list for PBXProject "KeyboardTextFieldDemo" */ = {
305 | isa = XCConfigurationList;
306 | buildConfigurations = (
307 | 22918F781A79C48300547672 /* Debug */,
308 | 22918F791A79C48300547672 /* Release */,
309 | );
310 | defaultConfigurationIsVisible = 0;
311 | defaultConfigurationName = Release;
312 | };
313 | 22918F7A1A79C48300547672 /* Build configuration list for PBXNativeTarget "KeyboardTextFieldDemo" */ = {
314 | isa = XCConfigurationList;
315 | buildConfigurations = (
316 | 22918F7B1A79C48300547672 /* Debug */,
317 | 22918F7C1A79C48300547672 /* Release */,
318 | );
319 | defaultConfigurationIsVisible = 0;
320 | defaultConfigurationName = Release;
321 | };
322 | /* End XCConfigurationList section */
323 | };
324 | rootObject = 22918F531A79C48200547672 /* Project object */;
325 | }
326 |
--------------------------------------------------------------------------------
/KeyboardTextField/KeyboardTextField.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyboardTextField.swift
3 | // DoudouApp
4 | // Version 3.2 iOS 8.0 and Swift 4 and Xcode9.2
5 | // Created by yushuyi on 15/1/17.
6 | // Copyright (c) 2015年 DoudouApp. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc public protocol KeyboardTextFieldDelegate : class {
12 |
13 | /**
14 | 点击左边按钮的委托
15 | */
16 | @objc optional func keyboardTextFieldPressLeftButton(_ keyboardTextField :KeyboardTextField)
17 |
18 | /**
19 | 点击右边按钮的委托
20 | */
21 | @objc optional func keyboardTextFieldPressRightButton(_ keyboardTextField :KeyboardTextField)
22 |
23 | /**
24 | 点击键盘上面的回车按钮响应委托
25 | */
26 | @objc optional func keyboardTextFieldPressReturnButton(_ keyboardTextField :KeyboardTextField)
27 |
28 | @objc optional func keyboardTextFieldWillBeginEditing(_ keyboardTextField :KeyboardTextField)
29 | @objc optional func keyboardTextFieldDidBeginEditing(_ keyboardTextField :KeyboardTextField)
30 |
31 | @objc optional func keyboardTextFieldWillEndEditing(_ keyboardTextField :KeyboardTextField)
32 | @objc optional func keyboardTextFieldDidEndEditing(_ keyboardTextField :KeyboardTextField)
33 |
34 |
35 | /**
36 | 键盘文本内容被改变时触发
37 | - parameter text: 本次写入的值
38 | */
39 | @objc optional func keyboardTextField(_ keyboardTextField :KeyboardTextField , didChangeText text:String)
40 |
41 | }
42 |
43 | fileprivate var KeyboardTextFieldDebugMode : Bool = false
44 |
45 | fileprivate var keyboardViewDefaultHeight : CGFloat = 48.0
46 | fileprivate let textViewDefaultHeight : CGFloat = 36.0
47 |
48 |
49 |
50 |
51 | open class KeyboardTextField: UIView {
52 |
53 | public enum AttachmentViewLocation {
54 | case up
55 | case down
56 | }
57 |
58 | //Delegate
59 | open weak var delegate : KeyboardTextFieldDelegate?
60 |
61 | //Init
62 | public convenience init(point : CGPoint,width : CGFloat) {
63 | self.init(frame: CGRect(x: point.x, y: point.y, width: width, height: keyboardViewDefaultHeight))
64 | }
65 |
66 | public required init?(coder aDecoder: NSCoder) {
67 | super.init(coder: aDecoder)
68 | }
69 |
70 | public override init(frame : CGRect) {
71 | super.init(frame : frame)
72 | keyboardViewDefaultHeight = frame.height
73 | backgroundColor = UIColor.red
74 |
75 | keyboardView.frame = bounds
76 | keyboardView.backgroundColor = UIColor.yellow
77 | addSubview(keyboardView)
78 |
79 | keyboardView.addSubview(textViewBackground)
80 |
81 | textView.font = UIFont.systemFont(ofSize: 15.0);
82 | textView.autocapitalizationType = .none
83 | textView.scrollIndicatorInsets = UIEdgeInsetsMake(0, -1, 0, 1);//滚动指示器 皮条
84 | textView.textContainerInset = UIEdgeInsetsMake(9.0, 3.0, 7.0, 0.0);
85 | textView.autocorrectionType = .no
86 | textView.keyboardType = UIKeyboardType.default;
87 | textView.returnKeyType = UIReturnKeyType.done;
88 | textView.enablesReturnKeyAutomatically = true;
89 | textView.delegate = self
90 | textView.textColor = UIColor(white: 0.200, alpha: 1.000)
91 | textView.backgroundColor = UIColor.green
92 | textView.addObserver(self, forKeyPath: "contentSize", options: NSKeyValueObservingOptions.new, context: nil)
93 | textView.scrollsToTop = false
94 | keyboardView.addSubview(textView)
95 |
96 | placeholderLabel.textAlignment = NSTextAlignment.left
97 | placeholderLabel.numberOfLines = 1
98 | placeholderLabel.backgroundColor = UIColor.clear
99 | placeholderLabel.textColor = UIColor.lightGray
100 | placeholderLabel.font = textView.font;
101 | placeholderLabel.isHidden = false
102 | placeholderLabel.text = "placeholder"
103 | textView.addSubview(placeholderLabel)
104 |
105 |
106 | leftButton.backgroundColor = UIColor.red
107 | leftButton.titleLabel?.font = UIFont.systemFont(ofSize: 14.0)
108 | leftButton.setTitle("Left", for: .normal)
109 | leftButton.addTarget(self, action: #selector(KeyboardTextField.leftButtonAction(_:)), for: UIControlEvents.touchUpInside)
110 | keyboardView.addSubview(leftButton)
111 |
112 | rightButton.backgroundColor = UIColor.red
113 | rightButton.titleLabel?.font = UIFont.systemFont(ofSize: 14.0)
114 | rightButton.setTitle("Right", for: .normal)
115 | rightButton.addTarget(self, action: #selector(KeyboardTextField.rightButtonAction(_:)), for: UIControlEvents.touchUpInside)
116 | keyboardView.addSubview(rightButton)
117 |
118 | registeringKeyboardNotification()
119 |
120 |
121 | //当键盘的高度改变时,keyboardTextField 会吸附会去,这的过程中间会看到底部 透明蒙层,效果不好 加上这个视图以作修饰
122 | bottomBackgroundView.frame = CGRect(x: 0, y: bounds.size.height, width: bounds.size.width, height: 100)
123 | bottomBackgroundView.autoresizingMask = [.flexibleTopMargin,.flexibleWidth]
124 | bottomBackgroundView.backgroundColor = UIColor(red: 210.0/255.0, green: 213.0/255.0, blue: 219.0/255.0, alpha: 1.0)
125 | bottomBackgroundView.isUserInteractionEnabled = false
126 | bottomBackgroundView.isHidden = true
127 | insertSubview(bottomBackgroundView, at: 0)
128 |
129 | }
130 |
131 | open func show() {
132 | textView.becomeFirstResponder()
133 | }
134 |
135 | open func hide() {
136 | if isAutoLayout {
137 | isAutoLayout = false
138 | translatesAutoresizingMaskIntoConstraints = false
139 | }
140 | attachmentView?.moveToBottom()
141 | delegate?.keyboardTextFieldWillEndEditing?(self)
142 | bottomBackgroundView.isHidden = true
143 | isEditing = false
144 | isHideing = true
145 |
146 | //这里判断一下键盘是否已经隐藏了,如果隐藏了 也需要调用一下 DidEnd回调以保证完整性
147 | if let superview = self.superview {
148 | if self.bottom == superview.bounds.size.height {
149 | delegate?.keyboardTextFieldDidEndEditing?(self)
150 | }
151 | }
152 |
153 | endEditing(true)
154 | setTapButtonHidden(true)
155 |
156 | }
157 |
158 | open func addAttachmentView(_ view: UIView,location: AttachmentViewLocation = .up) {
159 | removeAttachmentView()
160 | insertSubview(view, at: 0)
161 | view.alpha = 0
162 | view.isUserInteractionEnabled = false
163 | view.autoresizingMask = []
164 | attachmentView = view
165 | attachmentViewLocation = location
166 | }
167 |
168 | public func removeAttachmentView() {
169 | if let attachmentView = attachmentView {
170 | attachmentView.removeFromSuperview()
171 | self.attachmentView = nil
172 | }
173 | }
174 |
175 | public func done() {
176 | delegate?.keyboardTextFieldPressReturnButton?(self)
177 | }
178 |
179 | //Status
180 | public var isSending = false
181 |
182 | public var isEnabled: Bool = true {
183 | didSet {
184 | textView.isEditable = isEnabled
185 | leftButton.isEnabled = isEnabled
186 | rightButton.isEnabled = isEnabled
187 | }
188 | }
189 | public var isEditing: Bool = false
190 |
191 | public var isLeftButtonHidden : Bool = true {
192 | didSet {
193 | leftButton.isHidden = isLeftButtonHidden
194 | setNeedsLayout()
195 | }
196 | }
197 |
198 | public var isRightButtonHidden : Bool = true {
199 | didSet {
200 | rightButton.isHidden = isRightButtonHidden
201 | setNeedsLayout()
202 | }
203 | }
204 |
205 | public var attachmentViewLocation: AttachmentViewLocation = .up
206 |
207 | //text
208 | public var text : String! {
209 | get {
210 | return textView.text
211 | }
212 | set {
213 | textView.text = newValue
214 | textViewDidChange(textView)
215 | layoutIfNeeded()
216 | }
217 | }
218 |
219 | open var maxNumberOfWords : Int = 140
220 | open var minNumberOfWords : Int = 0
221 | open var maxNumberOfLines : Int = 4
222 |
223 |
224 | //UI
225 | public var attachmentView: UIView?
226 | public lazy var keyboardView = UIView()
227 | public lazy var textView : KeyboardTextView = KeyboardTextView()
228 | public lazy var placeholderLabel = UILabel()
229 | public lazy var textViewBackground = UIImageView()
230 | public lazy var leftButton = UIButton()
231 | public lazy var rightButton = UIButton()
232 | public lazy var bottomBackgroundView = UIView()
233 | public func clearTestColor() {
234 | backgroundColor = UIColor.clear
235 | leftButton.backgroundColor = UIColor.clear
236 | rightButton.backgroundColor = UIColor.clear
237 | textView.backgroundColor = UIColor.clear
238 | textViewBackground.backgroundColor = UIColor.clear
239 | }
240 | public var tapButtonBackgroundColor: UIColor = UIColor.clear
241 |
242 | //Layout
243 | fileprivate var lastKeyboardFrame : CGRect = CGRect.zero
244 |
245 | open var leftRightDistance : CGFloat = 8.0
246 | open var middleDistance : CGFloat = 8.0
247 |
248 | open var buttonMaxWidth : CGFloat = 65.0
249 | open var buttonMinWidth : CGFloat = 45.0
250 |
251 | open override func layoutSubviews() {
252 | super.layoutSubviews()
253 |
254 | if isEditing {
255 | switch attachmentViewLocation {
256 | case .up:
257 | keyboardView.frame = CGRect(x: 0, y: (attachmentView?.bounds.size.height ?? 0), width: bounds.size.width, height: bounds.size.height - (attachmentView?.bounds.size.height ?? 0))
258 | case .down:
259 | keyboardView.frame = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height - (attachmentView?.bounds.size.height ?? 0))
260 | }
261 | }else {
262 | keyboardView.frame = CGRect(x: 0, y: 0, width: bounds.size.width, height: bounds.size.height)
263 | }
264 |
265 | if isLeftButtonHidden == false {
266 | var leftButtonWidth : CGFloat = 0.0
267 | leftButton.sizeToFit()
268 | if (buttonMinWidth <= leftButton.bounds.size.width) {
269 | leftButtonWidth = leftButton.bounds.size.width + 10
270 | }else {
271 | leftButtonWidth = buttonMinWidth
272 | }
273 | if (leftButton.bounds.size.width > buttonMaxWidth)
274 | {
275 | leftButtonWidth = buttonMaxWidth
276 | }
277 | leftButton.frame = CGRect(x: leftRightDistance, y: 0, width: leftButtonWidth, height: textViewDefaultHeight);
278 | leftButton.ktf_toBottom(offset: (keyboardViewDefaultHeight - textViewDefaultHeight) / 2.0)
279 | }
280 |
281 | if isRightButtonHidden == false {
282 | var rightButtonWidth : CGFloat = 0.0
283 | rightButton.sizeToFit()
284 | if (buttonMinWidth <= rightButton.bounds.size.width) {
285 | rightButtonWidth = rightButton.bounds.size.width + 10;
286 | }else {
287 | rightButtonWidth = buttonMinWidth
288 | }
289 | if (rightButton.bounds.size.width > buttonMaxWidth)
290 | {
291 | rightButtonWidth = buttonMaxWidth;
292 | }
293 | rightButton.frame = CGRect(x: keyboardView.bounds.size.width - leftRightDistance - rightButtonWidth, y: 0, width: rightButtonWidth, height: textViewDefaultHeight);
294 | rightButton.ktf_toBottom(offset: (keyboardViewDefaultHeight - textViewDefaultHeight) / 2.0)
295 | }
296 |
297 | textView.frame =
298 | CGRect(
299 | x: (isLeftButtonHidden == false ? leftButton.frame.origin.x + leftButton.bounds.size.width + middleDistance : leftRightDistance + middleDistance),
300 | y: (keyboardViewDefaultHeight - textViewDefaultHeight) / 2.0 + 0.5,
301 | width: keyboardView.bounds.size.width
302 | - (isLeftButtonHidden == false ? leftButton.bounds.size.width + middleDistance:middleDistance)
303 | - (isRightButtonHidden == false ? rightButton.bounds.size.width + middleDistance:middleDistance)
304 | - leftRightDistance * 2,
305 | height:
306 | textView.ktf_numberOfLines() < maxNumberOfLines ?
307 | textViewCurrentHeightForLines(textView.ktf_numberOfLines()) :
308 | textViewCurrentHeightForLines(maxNumberOfLines)
309 | )
310 | textViewBackground.frame = textView.frame;
311 |
312 | if placeholderLabel.textAlignment == .left {
313 | placeholderLabel.sizeToFit()
314 | placeholderLabel.frame.origin = CGPoint(x: 8.0, y: (textViewDefaultHeight - placeholderLabel.bounds.size.height) / 2);
315 |
316 | }else if placeholderLabel.textAlignment == .center {
317 | placeholderLabel.frame = placeholderLabel.superview!.bounds
318 | }
319 |
320 |
321 | if let attachmentView = attachmentView {
322 | attachmentView.bounds.size.width = bounds.size.width
323 | switch attachmentViewLocation {
324 | case .up:
325 | attachmentView.frame.origin = CGPoint.zero
326 | case .down:
327 | attachmentView.frame.origin = CGPoint(x: 0, y: keyboardView.bounds.size.height)
328 | }
329 | }
330 |
331 | }
332 |
333 | deinit {
334 | if KeyboardTextFieldDebugMode {
335 | print("\(NSStringFromClass(classForCoder)) has release!")
336 | }
337 |
338 | NotificationCenter.default.removeObserver(self)
339 | }
340 |
341 | fileprivate var isHideing = false
342 | fileprivate var isShowing = false
343 | fileprivate var isAutoLayout = false
344 |
345 | }
346 |
347 | //MARK: TextViewHeight
348 | extension KeyboardTextField {
349 |
350 | fileprivate func textViewCurrentHeightForLines(_ numberOfLines : Int) -> CGFloat {
351 | var height = textViewDefaultHeight - textView.font!.lineHeight
352 | let lineTotalHeight = textView.font!.lineHeight * CGFloat(numberOfLines)
353 | height += CGFloat(roundf(Float(lineTotalHeight)))
354 | return CGFloat(Int(height));
355 | }
356 |
357 | fileprivate func appropriateInputbarHeight() -> CGFloat {
358 | var height : CGFloat = 0.0;
359 |
360 | if textView.ktf_numberOfLines() == 1 {
361 | height = textViewDefaultHeight;
362 | }else if textView.ktf_numberOfLines() < maxNumberOfLines {
363 | height = textViewCurrentHeightForLines(textView.ktf_numberOfLines())
364 | }
365 | else {
366 | height = textViewCurrentHeightForLines(maxNumberOfLines)
367 | }
368 |
369 | height += keyboardViewDefaultHeight - textViewDefaultHeight;
370 |
371 | if (height < keyboardViewDefaultHeight) {
372 | height = keyboardViewDefaultHeight;
373 | }
374 | return CGFloat(roundf(Float(height)));
375 | }
376 |
377 | override open func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
378 |
379 | guard let object = object as? KeyboardTextView,let change = change else { return }
380 |
381 | if object == textView && keyPath == "contentSize" {
382 | if KeyboardTextFieldDebugMode {
383 | if let sizeValue = (change[NSKeyValueChangeKey.newKey] as? NSValue)?.cgSizeValue {
384 | print("\(sizeValue)---\(appropriateInputbarHeight())")
385 | }
386 | }
387 |
388 | let newKeyboardHeight = appropriateInputbarHeight()
389 | if newKeyboardHeight != keyboardView.bounds.size.height && superview != nil {
390 | UIView.animate(withDuration: 0.2, delay: 0.0, options: UIViewAnimationOptions(), animations: { () -> Void in
391 | let lastKeyboardFrameHeight = (self.lastKeyboardFrame.origin.y == 0.0 ? self.superview!.bounds.size.height : self.lastKeyboardFrame.origin.y)
392 | if self.isEditing {
393 | self.frame = CGRect(x: self.frame.origin.x, y: lastKeyboardFrameHeight - newKeyboardHeight - (self.attachmentView?.bounds.size.height ?? 0), width: self.frame.size.width, height: newKeyboardHeight + (self.attachmentView?.bounds.size.height ?? 0))
394 | self.layoutIfNeeded()
395 | }else {
396 | self.frame = CGRect(x: self.frame.origin.x, y: lastKeyboardFrameHeight - newKeyboardHeight, width: self.frame.size.width, height: newKeyboardHeight)
397 | }
398 |
399 | }, completion:{_ in
400 | })
401 | }
402 | }
403 | }
404 | }
405 |
406 | //MARK: Keyboard Notification
407 | extension KeyboardTextField {
408 |
409 | public var keyboardAnimationOptions : UIViewAnimationOptions {
410 | return UIViewAnimationOptions(rawValue: (7 as UInt) << 16)
411 | }
412 | public var keyboardAnimationDuration : TimeInterval {
413 | return TimeInterval(0.25)
414 | }
415 |
416 | func registeringKeyboardNotification() {
417 | // Registering for keyboard notification.
418 |
419 | NotificationCenter.default.addObserver(self, selector: #selector(KeyboardTextField.keyboardWillChangeFrame(_:)),name:NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
420 | NotificationCenter.default.addObserver(self, selector: #selector(KeyboardTextField.keyboardDidChangeFrame(_:)),name:NSNotification.Name.UIKeyboardDidChangeFrame, object: nil)
421 |
422 | // Registering for orientation changes notification
423 | NotificationCenter.default.addObserver(self, selector: #selector(KeyboardTextField.willChangeStatusBarOrientation(_:)),name: NSNotification.Name.UIApplicationWillChangeStatusBarOrientation, object: nil)
424 |
425 | }
426 |
427 | @objc func keyboardWillChangeFrame(_ notification : Notification) {
428 | if window == nil { return }
429 | if !window!.isKeyWindow { return }
430 |
431 | guard let userInfo = notification.userInfo else { return }
432 | let keyboardFrameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue
433 | let keyboardFrame = keyboardFrameValue.cgRectValue
434 | lastKeyboardFrame = superview!.convert(keyboardFrame, from: UIApplication.shared.keyWindow)
435 | if KeyboardTextFieldDebugMode {
436 | print("keyboardFrame : \(keyboardFrame)")
437 | }
438 |
439 | UIView.animate(withDuration: keyboardAnimationDuration, delay: 0.0, options: keyboardAnimationOptions, animations: { () -> Void in
440 | if self.isEditing {
441 | self.frame.origin.y = self.lastKeyboardFrame.origin.y - self.keyboardView.bounds.size.height - (self.attachmentView?.bounds.size.height ?? 0)
442 | self.frame.size.height = self.keyboardView.bounds.size.height + (self.attachmentView?.bounds.size.height ?? 0)
443 | self.attachmentView?.alpha = 1
444 | self.attachmentView?.isUserInteractionEnabled = true
445 | }else {
446 | self.frame.origin.y = self.superview!.bounds.size.height - self.keyboardView.bounds.size.height
447 | self.frame.size.height = self.keyboardView.bounds.size.height
448 | self.keyboardView.frame = self.bounds
449 | self.attachmentView?.alpha = 0
450 | self.attachmentView?.isUserInteractionEnabled = false
451 | }
452 |
453 | }, completion: {_ in
454 | if !self.isEditing && self.isHideing {
455 | self.isHideing = false
456 | self.delegate?.keyboardTextFieldDidEndEditing?(self)
457 | }
458 | if self.isEditing && self.isShowing {
459 | self.attachmentView?.moveToTop()
460 | self.bottomBackgroundView.isHidden = false
461 | self.isShowing = false
462 | self.delegate?.keyboardTextFieldDidBeginEditing?(self)
463 | }
464 | })
465 | }
466 |
467 | @objc func keyboardDidChangeFrame(_ notification : Notification) {}
468 | @objc func willChangeStatusBarOrientation(_ notification : Notification) {}
469 |
470 | }
471 |
472 |
473 | //MARK: TapButtonAction
474 | extension KeyboardTextField {
475 |
476 | @objc func leftButtonAction(_ button : UIButton) {
477 | delegate?.keyboardTextFieldPressLeftButton?(self)
478 | }
479 |
480 | @objc func rightButtonAction(_ button : UIButton) {
481 | delegate?.keyboardTextFieldPressRightButton?(self)
482 | }
483 |
484 | fileprivate var tapButtonTag : Int { return 12345 }
485 | public var tapButton : UIButton { return superview!.viewWithTag(tapButtonTag) as! UIButton }
486 | @objc func tapAction(_ button : UIButton) {
487 | hide()
488 | }
489 |
490 | fileprivate func setTapButtonHidden(_ hidden : Bool) {
491 | if hidden == false {
492 | tapButton.isHidden = hidden
493 | if let tapButtonSuperView = tapButton.superview {
494 | tapButtonSuperView.insertSubview(tapButton, belowSubview: self)
495 | }
496 | tapButton.alpha = 0.0
497 | UIView.animate(withDuration: keyboardAnimationDuration, delay: 0.0, options: keyboardAnimationOptions, animations: { () -> Void in
498 | self.tapButton.alpha = 1.0
499 | }, completion: {_ in
500 |
501 | })
502 | }else {
503 | UIView.animate(withDuration: keyboardAnimationDuration, delay: 0.0, options: keyboardAnimationOptions, animations: { () -> Void in
504 | self.tapButton.alpha = 0.0
505 | }, completion: {_ in
506 | self.tapButton.isHidden = hidden
507 | })
508 | }
509 | }
510 |
511 | override open func didMoveToSuperview() {
512 | if let superview = superview {
513 | let tapButton = UIButton(frame: superview.bounds)
514 | tapButton.addTarget(self, action: #selector(KeyboardTextField.tapAction(_:)), for: UIControlEvents.touchUpInside)
515 | tapButton.tag = tapButtonTag
516 | tapButton.isHidden = true
517 | tapButton.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
518 | tapButton.backgroundColor = tapButtonBackgroundColor
519 | superview.insertSubview(tapButton, at: 0)
520 | }
521 | }
522 |
523 | override open func willMove(toSuperview newSuperview: UIView?) {
524 | if ((superview != nil) && newSuperview == nil) {
525 | superview?.viewWithTag(tapButtonTag)?.removeFromSuperview()
526 | textView.removeObserver(self, forKeyPath: "contentSize", context: nil)
527 | }
528 | }
529 | }
530 |
531 |
532 | //MARK: UITextViewDelegate
533 | extension KeyboardTextField : UITextViewDelegate {
534 |
535 | public func textViewDidChange(_ textView: UITextView) {
536 |
537 | if (textView.text.isEmpty) {
538 | placeholderLabel.alpha = 1
539 | }
540 | else {
541 | placeholderLabel.alpha = 0
542 | }
543 |
544 | delegate?.keyboardTextField?(self, didChangeText: textView.text)
545 | }
546 |
547 | public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
548 | if isEditing == false {
549 | if !translatesAutoresizingMaskIntoConstraints {
550 | isAutoLayout = true
551 | translatesAutoresizingMaskIntoConstraints = true
552 | }
553 | isShowing = true
554 | delegate?.keyboardTextFieldWillBeginEditing?(self)
555 | }
556 | isEditing = true
557 | setTapButtonHidden(false)
558 | return true
559 | }
560 |
561 | public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
562 | return true
563 | }
564 |
565 | public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
566 | if isSending { return false }
567 | if text == "\n" {
568 | if isSending == false {
569 | done()
570 | }
571 | return false
572 | }
573 | return true
574 | }
575 | }
576 |
577 | public final class KeyboardTextView : UITextView {
578 |
579 | private var hasDragging : Bool = false
580 |
581 | override open func layoutSubviews() {
582 | super.layoutSubviews()
583 | if isDragging == false {
584 | if hasDragging {
585 | let delayTime = DispatchTime.now() + Double(Int64(1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
586 | DispatchQueue.main.asyncAfter(deadline: delayTime) {
587 | self.hasDragging = false
588 | }
589 | }else {
590 | if selectedRange.location == text.count {
591 | contentOffset = CGPoint(x: contentOffset.x, y: (contentSize.height + 2) - bounds.size.height)
592 | }
593 | }
594 | }else {
595 | hasDragging = true
596 | }
597 | }
598 |
599 | }
600 |
601 | //MARK: UITextView extension
602 | extension UITextView {
603 |
604 | fileprivate func ktf_numberOfLines() -> Int {
605 | let text = self.text as NSString
606 | let textAttributes = [NSAttributedStringKey.font: font!]
607 | var width: CGFloat = UIEdgeInsetsInsetRect(frame, textContainerInset).width
608 | width -= 2.0 * textContainer.lineFragmentPadding
609 | let boundingRect: CGRect = text.boundingRect(with: CGSize(width:width,height:9999), options: [NSStringDrawingOptions.usesLineFragmentOrigin , NSStringDrawingOptions.usesFontLeading], attributes: textAttributes, context: nil)
610 | let line = boundingRect.height / font!.lineHeight
611 | if line < 1.0 { return 1 }
612 | return abs(Int(line))
613 | }
614 | }
615 |
616 | extension UIView {
617 | /**
618 | 将视图移动到父视图的底端
619 | - parameter offset: 可进行微调 大于0 则 小于0 则
620 | */
621 | fileprivate func ktf_toBottom(offset : CGFloat = 0.0) {
622 | if let superView = superview {
623 | frame.origin.y = superView.bounds.size.height - offset - frame.size.height;
624 | }
625 | }
626 |
627 | public func moveToTop() {
628 | superview?.bringSubview(toFront: self)
629 | }
630 |
631 | public func moveToBottom() {
632 | superview?.sendSubview(toBack: self)
633 | }
634 | }
635 |
--------------------------------------------------------------------------------