├── .gitignore
├── .swift-version
├── Example
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Info.plist
└── ViewController.swift
├── LICENSE.md
├── README.md
├── TextViewMaster.podspec
├── TextViewMaster.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── xcshareddata
│ └── xcschemes
│ └── JSGrowingTextView.xcscheme
├── TextViewMaster
├── Info.plist
├── TextViewMaster.h
└── TextViewMaster.swift
└── intro.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | tignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
2 |
3 | ## Build generated
4 | build/
5 | DerivedData/
6 |
7 | ## Various settings
8 | *.pbxuser
9 | !default.pbxuser
10 | *.mode1v3
11 | !default.mode1v3
12 | *.mode2v3
13 | !default.mode2v3
14 | *.perspectivev3
15 | !default.perspectivev3
16 | xcuserdata/
17 |
18 | ## Other
19 | *.moved-aside
20 | *.xccheckout
21 | *.xcscmblueprint
22 |
23 | ## Obj-C/Swift specific
24 | *.hmap
25 | *.ipa
26 | *.dSYM.zip
27 | *.dSYM
28 |
29 | ## Playgrounds
30 | timeline.xctimeline
31 | playground.xcworkspace
32 |
33 | # Swift Package Manager
34 | #
35 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
36 | # Packages/
37 | # Package.pins
38 | # Package.resolved
39 | .build/
40 |
41 | # CocoaPods
42 | #
43 | # We recommend against adding the Pods directory to your .gitignore. However
44 | # you should judge for yourself, the pros and cons are mentioned at:
45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
46 | #
47 | # Pods/
48 |
49 | # Carthage
50 | #
51 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
52 | # Carthage/Checkouts
53 |
54 | Carthage/Build
55 |
56 | # fastlane
57 | #
58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
59 | # screenshots whenever they are needed.
60 | # For more information about the recommended setup visit:
61 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
62 |
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 |
--------------------------------------------------------------------------------
/.swift-version:
--------------------------------------------------------------------------------
1 | 4.2
2 |
--------------------------------------------------------------------------------
/Example/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // Example
4 | //
5 | // Created by jeasung.lee on 2017. 12. 12..
6 | // Copyright © 2017년 jeasungLEE. 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: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
18 | return true
19 | }
20 |
21 | func applicationWillResignActive(_ application: UIApplication) {
22 | }
23 |
24 | func applicationDidEnterBackground(_ application: UIApplication) {
25 | }
26 |
27 | func applicationWillEnterForeground(_ application: UIApplication) {
28 | }
29 |
30 | func applicationDidBecomeActive(_ application: UIApplication) {
31 | }
32 |
33 | func applicationWillTerminate(_ application: UIApplication) {
34 | }
35 |
36 |
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/Example/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Example/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Example/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Example/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // Example
4 | //
5 | // Created by jeasung.lee on 2017. 12. 12..
6 | // Copyright © 2017년 jeasungLEE. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import TextViewMaster
11 |
12 | class ViewController: UIViewController {
13 | var bottomConstraint: NSLayoutConstraint?
14 | override func viewDidLoad() {
15 | super.viewDidLoad()
16 | let inputView = UIView()
17 | let textViewMaster = TextViewMaster()
18 | let sendLabel = UILabel()
19 |
20 | inputView.backgroundColor = .gray
21 | sendLabel.text = "send"
22 |
23 | textViewMaster.delegate = self
24 | textViewMaster.layer.cornerRadius = 5
25 | textViewMaster.isAnimate = true //에니메이션 사용여부
26 | textViewMaster.maxLength = 200 //최대 글자수
27 | textViewMaster.maxHeight = 500 //최대 높이 제한
28 | textViewMaster.placeHolder = "메세지를 입력해주세요." //플레이스홀더
29 | textViewMaster.placeHolderColor = UIColor(white: 0.8, alpha: 1.0) //플레이스홀더 색상
30 | textViewMaster.font = UIFont.systemFont(ofSize: 17)
31 |
32 | inputView.translatesAutoresizingMaskIntoConstraints = false
33 | textViewMaster.translatesAutoresizingMaskIntoConstraints = false
34 | sendLabel.translatesAutoresizingMaskIntoConstraints = false
35 |
36 | view.addSubview(inputView)
37 | inputView.addSubview(textViewMaster)
38 | inputView.addSubview(sendLabel)
39 |
40 | if #available(iOS 11.0, *) {
41 | inputView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
42 | bottomConstraint = inputView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
43 | inputView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
44 | } else {
45 | inputView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
46 | bottomConstraint = inputView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
47 | inputView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
48 | }
49 | bottomConstraint?.isActive = true
50 |
51 | sendLabel.bottomAnchor.constraint(equalTo: inputView.bottomAnchor).isActive = true
52 | sendLabel.trailingAnchor.constraint(equalTo: inputView.trailingAnchor, constant: -8).isActive = true
53 | sendLabel.widthAnchor.constraint(equalToConstant: 40).isActive = true
54 | sendLabel.heightAnchor.constraint(equalToConstant: 50).isActive = true
55 |
56 | textViewMaster.topAnchor.constraint(equalTo: inputView.topAnchor, constant: 8).isActive = true
57 | textViewMaster.leadingAnchor.constraint(equalTo: inputView.leadingAnchor, constant: 8).isActive = true
58 | textViewMaster.trailingAnchor.constraint(equalTo: sendLabel.leadingAnchor, constant: -8).isActive = true
59 | textViewMaster.bottomAnchor.constraint(equalTo: inputView.bottomAnchor, constant: -8).isActive = true
60 |
61 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChangeFrame), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
62 |
63 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapGestureHandler))
64 | view.addGestureRecognizer(tapGesture)
65 | }
66 |
67 | deinit {
68 | NotificationCenter.default.removeObserver(self)
69 | }
70 |
71 | @objc func keyboardWillChangeFrame(_ notification: Notification) {
72 | let endFrame = ((notification as NSNotification).userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
73 | bottomConstraint?.constant = -(view.bounds.height - endFrame.origin.y)
74 | self.view.layoutIfNeeded()
75 | }
76 |
77 | @objc func tapGestureHandler() {
78 | view.endEditing(true)
79 | }
80 |
81 | override func didReceiveMemoryWarning() {
82 | super.didReceiveMemoryWarning()
83 | }
84 | }
85 |
86 | extension ViewController: TextViewMasterDelegate {
87 | func growingTextView(growingTextView: TextViewMaster, willChangeHeight height: CGFloat) {
88 | self.view.layoutIfNeeded()
89 | }
90 | }
91 |
92 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 jeasungLEE
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TextViewMaster
2 | [](http://cocoapods.org/pods/TextViewMaster)
3 | [](https://github.com/jeasungLEE/TextViewMaster/blob/master/LICENSE)
4 | [](http://cocoapods.org/pods/TextViewMaster)
5 | [](https://developer.apple.com/swift/)
6 | ## Introduce
7 |
8 |
9 | Easy custom placeholder and growing textView
10 |
11 | You can easily adjust the color, font, and position of the placeholder.
12 | The height of the textview automatically changes every time you increase or decrease the line in the textview.
13 |
14 | ## Requirements
15 | * iOS9.0 or higher version
16 | * Swift4.2
17 |
18 |
19 | ## Installation
20 | ### Cocoapods
21 |
22 | TextViewMaster is available through [CocoaPods](http://cocoapods.org).
23 |
24 | ```ruby
25 | pod 'TextViewMaster'
26 | ```
27 |
28 | ## Usage
29 |
30 | ```ruby
31 | import TextViewMaster
32 | ```
33 | ### Customization
34 | ```ruby
35 | isAnimate: Bool = true //에니메이션 사용여부
36 | maxLength: Int = 0 //최대 글자수
37 | minHeight: CGFloat = 0 //최소 높이 제한
38 | maxHeight: CGFloat = 0 //최대 높이 제한
39 |
40 | placeHolder: String = "" //플레이스홀더
41 | placeHolderFont: UIFont = UIFont.systemFont(ofSize: 17) //플레이스홀더 폰트
42 | placeHolderColor: UIColor = UIColor(white: 0.8, alpha: 1.0) //플레이스홀더 컬러
43 | placeHolderTopPadding: CGFloat = 0 //플레이스홀더 위 여백
44 | placeHolderBottomPadding: CGFloat = 0 //플레이스홀더 아래 여백
45 | placeHolderRightPadding: CGFloat = 5 //플레이스홀더 오른쪽 여백
46 | placeHolderLeftPadding: CGFloat = 5 //플레이스홀더 왼쪽 여백
47 | ```
48 | ### Programmatically
49 | ```ruby
50 | let textViewMaster = TextViewMaster()
51 | textViewMaster.delegate = self
52 | inputView.addSubview(textViewMaster)
53 | ```
54 |
55 | If you have difficulty applying, please refer to the example folder.
56 |
57 | ### Storyboard
58 | 1. TextView Set class to "TextViewMaster".
59 | 2. Set delegate to it's view controller
60 |
61 | ### Delegate
62 | TextViewMaster inherits from UITextViewDelegate.
63 | You can also use UITextViewDelegate by default.
64 | Added or modified functions
65 | ```ruby
66 | func growingTextView(growingTextView: TextViewMaster, shouldChangeTextInRange range:NSRange, replacementText text:String) -> Bool
67 | func growingTextViewShouldReturn(growingTextView: TextViewMaster)
68 | func growingTextView(growingTextView: TextViewMaster, willChangeHeight height:CGFloat)
69 | func growingTextView(growingTextView: TextViewMaster, didChangeHeight height:CGFloat)
70 | ```
71 |
72 | ## Author
73 | [jeasungLEE](https://github.com/jeasungLEE)
74 |
75 | ## License
76 | TextViewMaster is available under the MIT license.
77 |
--------------------------------------------------------------------------------
/TextViewMaster.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # Be sure to run `pod spec lint TextViewMaster podspec' to ensure this is a
3 | # valid spec and to remove all comments including this before submitting the spec.
4 | #
5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html
6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/
7 | #
8 |
9 | Pod::Spec.new do |s|
10 |
11 |
12 | s.name = "TextViewMaster"
13 | s.version = "1.1.0"
14 | s.summary = "TextViewMaster."
15 | s.description = <<-DESC
16 | Easy custom placeholder and growing textView.
17 | DESC
18 | s.homepage = "https://github.com/JeaSungLEE/TextViewMaster"
19 | # s.screenshots = "https://github.com/JeaSungLEE/TextViewMaster/blob/master/intro.gif"
20 | s.license = { :type => "MIT", :file => "LICENSE.md" }
21 | s.author = { "jeasung.lee" => "wotjdzz1@naver.com" }
22 | s.platform = :ios, "9.0"
23 | s.source = { :git => "https://github.com/JeaSungLEE/TextViewMaster.git", :tag => "#{s.version}" }
24 | s.source_files = "TextViewMaster/**/*.swift"
25 |
26 | s.framework = "UIKit"
27 |
28 | s.requires_arc = true
29 |
30 | end
31 |
--------------------------------------------------------------------------------
/TextViewMaster.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 39AF2F6C1FDF922700F55150 /* TextViewMaster.h in Headers */ = {isa = PBXBuildFile; fileRef = 39AF2F6A1FDF922700F55150 /* TextViewMaster.h */; settings = {ATTRIBUTES = (Public, ); }; };
11 | 39AF2F731FDF923A00F55150 /* TextViewMaster.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AF2F721FDF923A00F55150 /* TextViewMaster.swift */; };
12 | 39AF2F7B1FDF924800F55150 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AF2F7A1FDF924800F55150 /* AppDelegate.swift */; };
13 | 39AF2F7D1FDF924800F55150 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39AF2F7C1FDF924800F55150 /* ViewController.swift */; };
14 | 39AF2F801FDF924800F55150 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39AF2F7E1FDF924800F55150 /* Main.storyboard */; };
15 | 39AF2F821FDF924800F55150 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 39AF2F811FDF924800F55150 /* Assets.xcassets */; };
16 | 39AF2F851FDF924800F55150 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 39AF2F831FDF924800F55150 /* LaunchScreen.storyboard */; };
17 | 4DA8CF6D21FAEFE1004153E6 /* TextViewMaster.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 39AF2F671FDF922700F55150 /* TextViewMaster.framework */; };
18 | /* End PBXBuildFile section */
19 |
20 | /* Begin PBXFileReference section */
21 | 39AF2F671FDF922700F55150 /* TextViewMaster.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TextViewMaster.framework; sourceTree = BUILT_PRODUCTS_DIR; };
22 | 39AF2F6A1FDF922700F55150 /* TextViewMaster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TextViewMaster.h; sourceTree = ""; };
23 | 39AF2F6B1FDF922700F55150 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
24 | 39AF2F721FDF923A00F55150 /* TextViewMaster.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewMaster.swift; sourceTree = ""; };
25 | 39AF2F781FDF924800F55150 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
26 | 39AF2F7A1FDF924800F55150 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
27 | 39AF2F7C1FDF924800F55150 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
28 | 39AF2F7F1FDF924800F55150 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
29 | 39AF2F811FDF924800F55150 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
30 | 39AF2F841FDF924800F55150 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
31 | 39AF2F861FDF924800F55150 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | /* End PBXFileReference section */
33 |
34 | /* Begin PBXFrameworksBuildPhase section */
35 | 39AF2F631FDF922700F55150 /* Frameworks */ = {
36 | isa = PBXFrameworksBuildPhase;
37 | buildActionMask = 2147483647;
38 | files = (
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | 39AF2F751FDF924800F55150 /* Frameworks */ = {
43 | isa = PBXFrameworksBuildPhase;
44 | buildActionMask = 2147483647;
45 | files = (
46 | 4DA8CF6D21FAEFE1004153E6 /* TextViewMaster.framework in Frameworks */,
47 | );
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | /* End PBXFrameworksBuildPhase section */
51 |
52 | /* Begin PBXGroup section */
53 | 39AF2F5D1FDF922700F55150 = {
54 | isa = PBXGroup;
55 | children = (
56 | 39AF2F691FDF922700F55150 /* TextViewMaster */,
57 | 39AF2F791FDF924800F55150 /* Example */,
58 | 39AF2F681FDF922700F55150 /* Products */,
59 | 4DA8CF6C21FAEFE1004153E6 /* Frameworks */,
60 | );
61 | sourceTree = "";
62 | };
63 | 39AF2F681FDF922700F55150 /* Products */ = {
64 | isa = PBXGroup;
65 | children = (
66 | 39AF2F671FDF922700F55150 /* TextViewMaster.framework */,
67 | 39AF2F781FDF924800F55150 /* Example.app */,
68 | );
69 | name = Products;
70 | sourceTree = "";
71 | };
72 | 39AF2F691FDF922700F55150 /* TextViewMaster */ = {
73 | isa = PBXGroup;
74 | children = (
75 | 39AF2F6A1FDF922700F55150 /* TextViewMaster.h */,
76 | 39AF2F6B1FDF922700F55150 /* Info.plist */,
77 | 39AF2F721FDF923A00F55150 /* TextViewMaster.swift */,
78 | );
79 | path = TextViewMaster;
80 | sourceTree = "";
81 | };
82 | 39AF2F791FDF924800F55150 /* Example */ = {
83 | isa = PBXGroup;
84 | children = (
85 | 39AF2F7A1FDF924800F55150 /* AppDelegate.swift */,
86 | 39AF2F7C1FDF924800F55150 /* ViewController.swift */,
87 | 39AF2F7E1FDF924800F55150 /* Main.storyboard */,
88 | 39AF2F811FDF924800F55150 /* Assets.xcassets */,
89 | 39AF2F831FDF924800F55150 /* LaunchScreen.storyboard */,
90 | 39AF2F861FDF924800F55150 /* Info.plist */,
91 | );
92 | path = Example;
93 | sourceTree = "";
94 | };
95 | 4DA8CF6C21FAEFE1004153E6 /* Frameworks */ = {
96 | isa = PBXGroup;
97 | children = (
98 | );
99 | name = Frameworks;
100 | sourceTree = "";
101 | };
102 | /* End PBXGroup section */
103 |
104 | /* Begin PBXHeadersBuildPhase section */
105 | 39AF2F641FDF922700F55150 /* Headers */ = {
106 | isa = PBXHeadersBuildPhase;
107 | buildActionMask = 2147483647;
108 | files = (
109 | 39AF2F6C1FDF922700F55150 /* TextViewMaster.h in Headers */,
110 | );
111 | runOnlyForDeploymentPostprocessing = 0;
112 | };
113 | /* End PBXHeadersBuildPhase section */
114 |
115 | /* Begin PBXNativeTarget section */
116 | 39AF2F661FDF922700F55150 /* TextViewMaster */ = {
117 | isa = PBXNativeTarget;
118 | buildConfigurationList = 39AF2F6F1FDF922700F55150 /* Build configuration list for PBXNativeTarget "TextViewMaster" */;
119 | buildPhases = (
120 | 39AF2F621FDF922700F55150 /* Sources */,
121 | 39AF2F631FDF922700F55150 /* Frameworks */,
122 | 39AF2F641FDF922700F55150 /* Headers */,
123 | 39AF2F651FDF922700F55150 /* Resources */,
124 | );
125 | buildRules = (
126 | );
127 | dependencies = (
128 | );
129 | name = TextViewMaster;
130 | productName = JSGrowingTextView;
131 | productReference = 39AF2F671FDF922700F55150 /* TextViewMaster.framework */;
132 | productType = "com.apple.product-type.framework";
133 | };
134 | 39AF2F771FDF924800F55150 /* Example */ = {
135 | isa = PBXNativeTarget;
136 | buildConfigurationList = 39AF2F871FDF924800F55150 /* Build configuration list for PBXNativeTarget "Example" */;
137 | buildPhases = (
138 | 39AF2F741FDF924800F55150 /* Sources */,
139 | 39AF2F751FDF924800F55150 /* Frameworks */,
140 | 39AF2F761FDF924800F55150 /* Resources */,
141 | );
142 | buildRules = (
143 | );
144 | dependencies = (
145 | );
146 | name = Example;
147 | productName = Example;
148 | productReference = 39AF2F781FDF924800F55150 /* Example.app */;
149 | productType = "com.apple.product-type.application";
150 | };
151 | /* End PBXNativeTarget section */
152 |
153 | /* Begin PBXProject section */
154 | 39AF2F5E1FDF922700F55150 /* Project object */ = {
155 | isa = PBXProject;
156 | attributes = {
157 | LastSwiftUpdateCheck = 0920;
158 | LastUpgradeCheck = 1010;
159 | ORGANIZATIONNAME = jeasungLEE;
160 | TargetAttributes = {
161 | 39AF2F661FDF922700F55150 = {
162 | CreatedOnToolsVersion = 9.2;
163 | LastSwiftMigration = 0920;
164 | ProvisioningStyle = Automatic;
165 | };
166 | 39AF2F771FDF924800F55150 = {
167 | CreatedOnToolsVersion = 9.2;
168 | ProvisioningStyle = Automatic;
169 | };
170 | };
171 | };
172 | buildConfigurationList = 39AF2F611FDF922700F55150 /* Build configuration list for PBXProject "TextViewMaster" */;
173 | compatibilityVersion = "Xcode 8.0";
174 | developmentRegion = en;
175 | hasScannedForEncodings = 0;
176 | knownRegions = (
177 | en,
178 | Base,
179 | );
180 | mainGroup = 39AF2F5D1FDF922700F55150;
181 | productRefGroup = 39AF2F681FDF922700F55150 /* Products */;
182 | projectDirPath = "";
183 | projectRoot = "";
184 | targets = (
185 | 39AF2F661FDF922700F55150 /* TextViewMaster */,
186 | 39AF2F771FDF924800F55150 /* Example */,
187 | );
188 | };
189 | /* End PBXProject section */
190 |
191 | /* Begin PBXResourcesBuildPhase section */
192 | 39AF2F651FDF922700F55150 /* Resources */ = {
193 | isa = PBXResourcesBuildPhase;
194 | buildActionMask = 2147483647;
195 | files = (
196 | );
197 | runOnlyForDeploymentPostprocessing = 0;
198 | };
199 | 39AF2F761FDF924800F55150 /* Resources */ = {
200 | isa = PBXResourcesBuildPhase;
201 | buildActionMask = 2147483647;
202 | files = (
203 | 39AF2F851FDF924800F55150 /* LaunchScreen.storyboard in Resources */,
204 | 39AF2F821FDF924800F55150 /* Assets.xcassets in Resources */,
205 | 39AF2F801FDF924800F55150 /* Main.storyboard in Resources */,
206 | );
207 | runOnlyForDeploymentPostprocessing = 0;
208 | };
209 | /* End PBXResourcesBuildPhase section */
210 |
211 | /* Begin PBXSourcesBuildPhase section */
212 | 39AF2F621FDF922700F55150 /* Sources */ = {
213 | isa = PBXSourcesBuildPhase;
214 | buildActionMask = 2147483647;
215 | files = (
216 | 39AF2F731FDF923A00F55150 /* TextViewMaster.swift in Sources */,
217 | );
218 | runOnlyForDeploymentPostprocessing = 0;
219 | };
220 | 39AF2F741FDF924800F55150 /* Sources */ = {
221 | isa = PBXSourcesBuildPhase;
222 | buildActionMask = 2147483647;
223 | files = (
224 | 39AF2F7D1FDF924800F55150 /* ViewController.swift in Sources */,
225 | 39AF2F7B1FDF924800F55150 /* AppDelegate.swift in Sources */,
226 | );
227 | runOnlyForDeploymentPostprocessing = 0;
228 | };
229 | /* End PBXSourcesBuildPhase section */
230 |
231 | /* Begin PBXVariantGroup section */
232 | 39AF2F7E1FDF924800F55150 /* Main.storyboard */ = {
233 | isa = PBXVariantGroup;
234 | children = (
235 | 39AF2F7F1FDF924800F55150 /* Base */,
236 | );
237 | name = Main.storyboard;
238 | sourceTree = "";
239 | };
240 | 39AF2F831FDF924800F55150 /* LaunchScreen.storyboard */ = {
241 | isa = PBXVariantGroup;
242 | children = (
243 | 39AF2F841FDF924800F55150 /* Base */,
244 | );
245 | name = LaunchScreen.storyboard;
246 | sourceTree = "";
247 | };
248 | /* End PBXVariantGroup section */
249 |
250 | /* Begin XCBuildConfiguration section */
251 | 39AF2F6D1FDF922700F55150 /* Debug */ = {
252 | isa = XCBuildConfiguration;
253 | buildSettings = {
254 | ALWAYS_SEARCH_USER_PATHS = NO;
255 | CLANG_ANALYZER_NONNULL = YES;
256 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
257 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
258 | CLANG_CXX_LIBRARY = "libc++";
259 | CLANG_ENABLE_MODULES = YES;
260 | CLANG_ENABLE_OBJC_ARC = YES;
261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
262 | CLANG_WARN_BOOL_CONVERSION = YES;
263 | CLANG_WARN_COMMA = YES;
264 | CLANG_WARN_CONSTANT_CONVERSION = YES;
265 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
267 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
268 | CLANG_WARN_EMPTY_BODY = YES;
269 | CLANG_WARN_ENUM_CONVERSION = YES;
270 | CLANG_WARN_INFINITE_RECURSION = YES;
271 | CLANG_WARN_INT_CONVERSION = YES;
272 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
273 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
274 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
277 | CLANG_WARN_STRICT_PROTOTYPES = YES;
278 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
279 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
280 | CLANG_WARN_UNREACHABLE_CODE = YES;
281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
282 | CODE_SIGN_IDENTITY = "iPhone Developer";
283 | COPY_PHASE_STRIP = NO;
284 | CURRENT_PROJECT_VERSION = 1;
285 | DEBUG_INFORMATION_FORMAT = dwarf;
286 | ENABLE_STRICT_OBJC_MSGSEND = YES;
287 | ENABLE_TESTABILITY = YES;
288 | GCC_C_LANGUAGE_STANDARD = gnu11;
289 | GCC_DYNAMIC_NO_PIC = NO;
290 | GCC_NO_COMMON_BLOCKS = YES;
291 | GCC_OPTIMIZATION_LEVEL = 0;
292 | GCC_PREPROCESSOR_DEFINITIONS = (
293 | "DEBUG=1",
294 | "$(inherited)",
295 | );
296 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
297 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
298 | GCC_WARN_UNDECLARED_SELECTOR = YES;
299 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
300 | GCC_WARN_UNUSED_FUNCTION = YES;
301 | GCC_WARN_UNUSED_VARIABLE = YES;
302 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
303 | MTL_ENABLE_DEBUG_INFO = YES;
304 | ONLY_ACTIVE_ARCH = YES;
305 | SDKROOT = iphoneos;
306 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
307 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
308 | VERSIONING_SYSTEM = "apple-generic";
309 | VERSION_INFO_PREFIX = "";
310 | };
311 | name = Debug;
312 | };
313 | 39AF2F6E1FDF922700F55150 /* Release */ = {
314 | isa = XCBuildConfiguration;
315 | buildSettings = {
316 | ALWAYS_SEARCH_USER_PATHS = NO;
317 | CLANG_ANALYZER_NONNULL = YES;
318 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
319 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
320 | CLANG_CXX_LIBRARY = "libc++";
321 | CLANG_ENABLE_MODULES = YES;
322 | CLANG_ENABLE_OBJC_ARC = YES;
323 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
324 | CLANG_WARN_BOOL_CONVERSION = YES;
325 | CLANG_WARN_COMMA = YES;
326 | CLANG_WARN_CONSTANT_CONVERSION = YES;
327 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
329 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
330 | CLANG_WARN_EMPTY_BODY = YES;
331 | CLANG_WARN_ENUM_CONVERSION = YES;
332 | CLANG_WARN_INFINITE_RECURSION = YES;
333 | CLANG_WARN_INT_CONVERSION = YES;
334 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
335 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
336 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
337 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
338 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
339 | CLANG_WARN_STRICT_PROTOTYPES = YES;
340 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
341 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
342 | CLANG_WARN_UNREACHABLE_CODE = YES;
343 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
344 | CODE_SIGN_IDENTITY = "iPhone Developer";
345 | COPY_PHASE_STRIP = NO;
346 | CURRENT_PROJECT_VERSION = 1;
347 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
348 | ENABLE_NS_ASSERTIONS = NO;
349 | ENABLE_STRICT_OBJC_MSGSEND = YES;
350 | GCC_C_LANGUAGE_STANDARD = gnu11;
351 | GCC_NO_COMMON_BLOCKS = YES;
352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
354 | GCC_WARN_UNDECLARED_SELECTOR = YES;
355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
356 | GCC_WARN_UNUSED_FUNCTION = YES;
357 | GCC_WARN_UNUSED_VARIABLE = YES;
358 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
359 | MTL_ENABLE_DEBUG_INFO = NO;
360 | SDKROOT = iphoneos;
361 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
362 | VALIDATE_PRODUCT = YES;
363 | VERSIONING_SYSTEM = "apple-generic";
364 | VERSION_INFO_PREFIX = "";
365 | };
366 | name = Release;
367 | };
368 | 39AF2F701FDF922700F55150 /* Debug */ = {
369 | isa = XCBuildConfiguration;
370 | buildSettings = {
371 | APPLICATION_EXTENSION_API_ONLY = NO;
372 | CLANG_ENABLE_MODULES = YES;
373 | CODE_SIGN_IDENTITY = "";
374 | CODE_SIGN_STYLE = Automatic;
375 | DEFINES_MODULE = YES;
376 | DYLIB_COMPATIBILITY_VERSION = 1;
377 | DYLIB_CURRENT_VERSION = 1;
378 | DYLIB_INSTALL_NAME_BASE = "@rpath";
379 | INFOPLIST_FILE = "$(SRCROOT)/TextViewMaster/Info.plist";
380 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
381 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
382 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
383 | PRODUCT_BUNDLE_IDENTIFIER = co.kr.kaskay.JSGrowingTextView;
384 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
385 | SKIP_INSTALL = YES;
386 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
387 | SWIFT_VERSION = 4.2;
388 | TARGETED_DEVICE_FAMILY = "1,2";
389 | };
390 | name = Debug;
391 | };
392 | 39AF2F711FDF922700F55150 /* Release */ = {
393 | isa = XCBuildConfiguration;
394 | buildSettings = {
395 | APPLICATION_EXTENSION_API_ONLY = NO;
396 | CLANG_ENABLE_MODULES = YES;
397 | CODE_SIGN_IDENTITY = "";
398 | CODE_SIGN_STYLE = Automatic;
399 | DEFINES_MODULE = YES;
400 | DYLIB_COMPATIBILITY_VERSION = 1;
401 | DYLIB_CURRENT_VERSION = 1;
402 | DYLIB_INSTALL_NAME_BASE = "@rpath";
403 | INFOPLIST_FILE = "$(SRCROOT)/TextViewMaster/Info.plist";
404 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
405 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
406 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
407 | PRODUCT_BUNDLE_IDENTIFIER = co.kr.kaskay.JSGrowingTextView;
408 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
409 | SKIP_INSTALL = YES;
410 | SWIFT_VERSION = 4.2;
411 | TARGETED_DEVICE_FAMILY = "1,2";
412 | };
413 | name = Release;
414 | };
415 | 39AF2F881FDF924800F55150 /* Debug */ = {
416 | isa = XCBuildConfiguration;
417 | buildSettings = {
418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
419 | CODE_SIGN_STYLE = Automatic;
420 | INFOPLIST_FILE = Example/Info.plist;
421 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
422 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
423 | PRODUCT_BUNDLE_IDENTIFIER = co.kr.kaskay.Example;
424 | PRODUCT_NAME = "$(TARGET_NAME)";
425 | SWIFT_VERSION = 4.2;
426 | TARGETED_DEVICE_FAMILY = "1,2";
427 | };
428 | name = Debug;
429 | };
430 | 39AF2F891FDF924800F55150 /* Release */ = {
431 | isa = XCBuildConfiguration;
432 | buildSettings = {
433 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
434 | CODE_SIGN_STYLE = Automatic;
435 | INFOPLIST_FILE = Example/Info.plist;
436 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
437 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
438 | PRODUCT_BUNDLE_IDENTIFIER = co.kr.kaskay.Example;
439 | PRODUCT_NAME = "$(TARGET_NAME)";
440 | SWIFT_VERSION = 4.2;
441 | TARGETED_DEVICE_FAMILY = "1,2";
442 | };
443 | name = Release;
444 | };
445 | /* End XCBuildConfiguration section */
446 |
447 | /* Begin XCConfigurationList section */
448 | 39AF2F611FDF922700F55150 /* Build configuration list for PBXProject "TextViewMaster" */ = {
449 | isa = XCConfigurationList;
450 | buildConfigurations = (
451 | 39AF2F6D1FDF922700F55150 /* Debug */,
452 | 39AF2F6E1FDF922700F55150 /* Release */,
453 | );
454 | defaultConfigurationIsVisible = 0;
455 | defaultConfigurationName = Release;
456 | };
457 | 39AF2F6F1FDF922700F55150 /* Build configuration list for PBXNativeTarget "TextViewMaster" */ = {
458 | isa = XCConfigurationList;
459 | buildConfigurations = (
460 | 39AF2F701FDF922700F55150 /* Debug */,
461 | 39AF2F711FDF922700F55150 /* Release */,
462 | );
463 | defaultConfigurationIsVisible = 0;
464 | defaultConfigurationName = Release;
465 | };
466 | 39AF2F871FDF924800F55150 /* Build configuration list for PBXNativeTarget "Example" */ = {
467 | isa = XCConfigurationList;
468 | buildConfigurations = (
469 | 39AF2F881FDF924800F55150 /* Debug */,
470 | 39AF2F891FDF924800F55150 /* Release */,
471 | );
472 | defaultConfigurationIsVisible = 0;
473 | defaultConfigurationName = Release;
474 | };
475 | /* End XCConfigurationList section */
476 | };
477 | rootObject = 39AF2F5E1FDF922700F55150 /* Project object */;
478 | }
479 |
--------------------------------------------------------------------------------
/TextViewMaster.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TextViewMaster.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TextViewMaster.xcodeproj/xcshareddata/xcschemes/JSGrowingTextView.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
70 |
71 |
72 |
73 |
75 |
76 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/TextViewMaster/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.1
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TextViewMaster/TextViewMaster.h:
--------------------------------------------------------------------------------
1 | //
2 | // JSGrowingTextView.h
3 | // JSGrowingTextView
4 | //
5 | // Created by jeasung.lee on 2017. 12. 12..
6 | // Copyright © 2017년 jeasungLEE. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for JSGrowingTextView.
12 | FOUNDATION_EXPORT double JSGrowingTextViewVersionNumber;
13 |
14 | //! Project version string for JSGrowingTextView.
15 | FOUNDATION_EXPORT const unsigned char JSGrowingTextViewVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/TextViewMaster/TextViewMaster.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSGrowingTextView.swift
3 | // JSGrowingTextView
4 | //
5 | // Created by jeasung.lee on 2017. 12. 12..
6 | // Copyright © 2017년 jeasungLEE. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @objc public protocol TextViewMasterDelegate: UITextViewDelegate {
12 | @objc optional func growingTextView(growingTextView: TextViewMaster, shouldChangeTextInRange range:NSRange, replacementText text:String) -> Bool
13 | @objc optional func growingTextViewShouldReturn(growingTextView: TextViewMaster)
14 |
15 | @objc optional func growingTextView(growingTextView: TextViewMaster, willChangeHeight height:CGFloat)
16 | @objc optional func growingTextView(growingTextView: TextViewMaster, didChangeHeight height:CGFloat)
17 | }
18 |
19 | //MARK: -
20 | public class TextViewMaster: UITextView {
21 | public var isAnimate: Bool = true //에니메이션 사용여부
22 | public var maxLength: Int = 0 //최대 글자수
23 | public var minHeight: CGFloat = 0 //최소 높이 제한
24 | public var maxHeight: CGFloat = 0 //최대 높이 제한
25 |
26 | public var placeHolder: String = "" //플레이스홀더
27 | public var placeHolderFont: UIFont = UIFont.systemFont(ofSize: 17) //플레이스홀더 폰트
28 | public var placeHolderColor: UIColor = UIColor(white: 0.8, alpha: 1.0) //플레이스홀더 컬러
29 | public var placeHolderTopPadding: CGFloat = 0 //플레이스홀더 위 여백
30 | public var placeHolderBottomPadding: CGFloat = 0 //플레이스홀더 아래 여백
31 | public var placeHolderRightPadding: CGFloat = 5 //플레이스홀더 오른쪽 여백
32 | public var placeHolderLeftPadding: CGFloat = 5 //플레이스홀더 왼쪽 여백
33 |
34 | private weak var heightConstraint: NSLayoutConstraint?
35 |
36 | //MARK: - init
37 | override public init(frame: CGRect, textContainer: NSTextContainer?) {
38 | super.init(frame: frame, textContainer: textContainer)
39 | commonInit()
40 | }
41 |
42 | required public init?(coder aDecoder: NSCoder) {
43 | super.init(coder: aDecoder)
44 | commonInit()
45 | }
46 |
47 | private func commonInit() {
48 | contentMode = .redraw
49 | NotificationCenter.default.addObserver(self, selector: #selector(textDidChange), name: UITextView.textDidChangeNotification, object: self)
50 | NotificationCenter.default.addObserver(self, selector: #selector(textDidEndEditing), name: UITextView.textDidEndEditingNotification, object: self)
51 | }
52 |
53 | deinit {
54 | NotificationCenter.default.removeObserver(self)
55 | }
56 |
57 | //MARK: - override
58 | override public func layoutSubviews() {
59 | super.layoutSubviews()
60 | let height = checkHeightConstraint()
61 | setNewHieghtConstraintConstant(with: height)
62 |
63 | if isAnimate {
64 | UIView.animate(withDuration: 0.1, delay: 0.0, options: .curveLinear, animations: { [weak self] in
65 | guard let self = self, let delegate = self.delegate as? TextViewMasterDelegate else { return }
66 | delegate.growingTextView?(growingTextView: self, willChangeHeight: height)
67 | self.scrollToBottom()
68 | }) { [weak self] _ in
69 | guard let self = self, let delegate = self.delegate as? TextViewMasterDelegate else { return }
70 | delegate.growingTextView?(growingTextView: self, didChangeHeight: height)
71 | }
72 | } else {
73 | guard let delegate = delegate as? TextViewMasterDelegate else { return }
74 | delegate.growingTextView?(growingTextView: self, willChangeHeight: height)
75 | self.scrollToBottom()
76 | delegate.growingTextView?(growingTextView: self, didChangeHeight: height)
77 | }
78 | }
79 |
80 | override public func draw(_ rect: CGRect) {
81 | super.draw(rect)
82 | if text.isEmpty {
83 | drawPlaceHolder(rect)
84 | }
85 | }
86 | }
87 |
88 | //MARK: - custom func
89 | extension TextViewMaster {
90 | private func checkHeightConstraint() -> CGFloat {
91 | let height = getHieght()
92 |
93 | if heightConstraint == nil {
94 | setHeightConstraint(with: height)
95 | }
96 |
97 | return height
98 | }
99 |
100 | private func setNewHieghtConstraintConstant(with constant: CGFloat) {
101 | guard constant != heightConstraint?.constant else { return }
102 | heightConstraint?.constant = constant
103 | }
104 |
105 | private func getHieght() -> CGFloat {
106 | let size = sizeThatFits(CGSize(width: bounds.size.width, height: CGFloat.greatestFiniteMagnitude))
107 | var height = size.height
108 |
109 | height = minHeight > 0 ? max(height, minHeight) : height
110 | height = maxHeight > 0 ? min(height, maxHeight) : height
111 |
112 | return height
113 | }
114 |
115 | private func setHeightConstraint(with height: CGFloat) {
116 | heightConstraint = self.heightAnchor.constraint(equalToConstant: height)
117 | addConstraint(heightConstraint!)
118 | }
119 |
120 | private func scrollToBottom() {
121 | let bottom = self.contentSize.height - self.bounds.size.height
122 | self.setContentOffset(CGPoint(x: 0, y: bottom), animated: false)
123 | }
124 |
125 | private func getPlaceHolderAttribues() -> [NSAttributedString.Key: Any] {
126 | let paragraphStyle = NSMutableParagraphStyle()
127 | paragraphStyle.alignment = textAlignment
128 | var attributes: [NSAttributedString.Key: Any] = [
129 | .foregroundColor: placeHolderColor,
130 | .paragraphStyle: paragraphStyle
131 | ]
132 | attributes[.font] = placeHolderFont
133 |
134 | return attributes
135 | }
136 |
137 | private func drawPlaceHolder(_ rect: CGRect) {
138 | let xValue = textContainerInset.left + placeHolderLeftPadding
139 | let yValue = textContainerInset.top + placeHolderTopPadding
140 | let width = rect.size.width - xValue - (textContainerInset.right + placeHolderRightPadding)
141 | let height = rect.size.height - yValue - (textContainerInset.bottom + placeHolderBottomPadding)
142 | let placeHolderRect = CGRect(x: xValue, y: yValue, width: width, height: height)
143 |
144 | guard let gc = UIGraphicsGetCurrentContext() else { return }
145 | gc.saveGState()
146 | defer { gc.restoreGState() }
147 |
148 | placeHolder.draw(in: placeHolderRect, withAttributes: getPlaceHolderAttribues())
149 |
150 | }
151 | }
152 |
153 | //MARK: - NotificationCenter
154 | extension TextViewMaster {
155 | @objc private func textDidEndEditing(notification: Notification) {
156 | scrollToBottom()
157 | }
158 |
159 | @objc private func textDidChange(notification: Notification) {
160 | if let sender = notification.object as? TextViewMaster, sender == self {
161 | if maxLength > 0 && text.count > maxLength {
162 | let endIndex = text.index(text.startIndex, offsetBy: maxLength)
163 | text = String(text[.. Bool {
173 | guard textView.hasText || text != "" else { return false }
174 | if let delegate = delegate as? TextViewMasterDelegate {
175 | guard let value = delegate.growingTextView?(growingTextView: self, shouldChangeTextInRange: range, replacementText: text) else { return false }
176 | return value
177 | }
178 |
179 | if text == "\n" {
180 | if let delegate = delegate as? TextViewMasterDelegate {
181 | delegate.growingTextViewShouldReturn?(growingTextView: self)
182 | return true
183 | } else {
184 | textView.resignFirstResponder()
185 | return false
186 | }
187 | }
188 |
189 | return true
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/intro.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JeaSungLEE/TextViewMaster/f3258542ffd063f098f3378a6b53ab3c849ff981/intro.gif
--------------------------------------------------------------------------------