├── ZLYTextDemo.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── GL.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
├── xcuserdata
│ └── GL.xcuserdatad
│ │ └── xcschemes
│ │ ├── xcschememanagement.plist
│ │ └── ZLYTextDemo.xcscheme
└── project.pbxproj
├── ZLYTextDemo
├── ViewController.h
├── AppDelegate.h
├── main.m
├── ZLYTextField.h
├── ZLYTextView.h
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── Info.plist
├── AppDelegate.m
├── ViewController.m
├── ZLYTextField.m
└── ZLYTextView.m
├── ZLYTextDemoTests
├── Info.plist
└── ZLYTextDemoTests.m
└── ZLYTextDemoUITests
├── Info.plist
└── ZLYTextDemoUITests.m
/ZLYTextDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ZLYTextDemo.xcodeproj/project.xcworkspace/xcuserdata/GL.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zly775759507/ZLYTextField/HEAD/ZLYTextDemo.xcodeproj/project.xcworkspace/xcuserdata/GL.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ZLYTextDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // ZLYTextDemo
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 |
12 | @interface ViewController : UIViewController
13 |
14 |
15 |
16 |
17 | @end
18 |
19 |
--------------------------------------------------------------------------------
/ZLYTextDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ZLYTextDemo
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/ZLYTextDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ZLYTextDemo
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ZLYTextDemoTests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ZLYTextDemoUITests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ZLYTextDemo.xcodeproj/xcuserdata/GL.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ZLYTextDemo.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 679ADE941BE8B69F009D08A9
16 |
17 | primary
18 |
19 |
20 | 679ADEAD1BE8B6A0009D08A9
21 |
22 | primary
23 |
24 |
25 | 679ADEB81BE8B6A0009D08A9
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/ZLYTextDemoTests/ZLYTextDemoTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZLYTextDemoTests.m
3 | // ZLYTextDemoTests
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ZLYTextDemoTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ZLYTextDemoTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/ZLYTextDemo/ZLYTextField.h:
--------------------------------------------------------------------------------
1 | //
2 | // WordlimitTextField.h
3 | // TextFieldExtesion
4 | //
5 | // Created by zly on 15/10/29.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ZLYTextField;
12 | @protocol ZLYTextFieldDelegate
13 | @optional
14 | -(void)textFieldReturnKeyPress:(ZLYTextField *)textField;
15 | @end
16 |
17 |
18 | @interface ZLYTextField : UITextField
19 |
20 | typedef NS_ENUM(NSInteger, LimitType)
21 | {
22 | //截取字符串
23 | InterceptionString = 0,
24 | //无法输入
25 | UnableToEnter = 1
26 | };
27 |
28 | //textfield能够输入的最大字符串长度
29 | @property (assign , nonatomic) NSInteger MaxWordNumber;
30 | //长度限制样式
31 | @property (assign , nonatomic) LimitType LimiType; // default is 0
32 | //是否筛除emoji表情
33 | @property (assign , nonatomic) BOOL isEmoticons; // default is NO
34 | //textfield输入内容的起始坐标
35 | @property (nonatomic ) CGPoint textPoint; // default is (8,8)
36 | //可输入字数
37 | @property (assign , nonatomic) NSInteger canEnterWordsNumber;
38 |
39 | @property (nonatomic, weak) id returnDelegate;
40 |
41 |
42 | //获取光标位置
43 | - (NSRange) selectedRange;
44 | //设置光标位置
45 | - (void) setSelectedRange:(NSRange) range;
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/ZLYTextDemo/ZLYTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // WordlimitTextView.h
3 | // TextFieldExtesion
4 | //
5 | // Created by zly on 15/10/29.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class ZLYTextView;
12 | @protocol ZLYTextViewDelegate
13 | @optional
14 | -(void)textViewReturnKeyPress:(ZLYTextView *)textView;
15 | -(void)lwTextViewDidChange:(ZLYTextView *)textView;
16 | @end
17 |
18 | @interface ZLYTextView : UITextView
19 |
20 | typedef NS_ENUM(NSInteger, LimitTextType)
21 | {
22 | //截取字符串
23 | InterceptionStringTextView = 0,
24 | //无法输入
25 | UnableToEnterTextView = 1
26 | };
27 |
28 |
29 | //textview能够输入的最大字符串长度
30 | @property (assign , nonatomic) NSInteger MaxWordNumber;
31 | //长度限制样式
32 | @property (assign , nonatomic) LimitTextType LimiType; // default is 0
33 | //是否筛除emoji表情
34 | @property (assign , nonatomic) BOOL isEmoticons; // default is NO
35 | //textfield输入内容的起始坐标
36 | @property (nonatomic ) CGPoint textPoint; // default is (8,8)
37 | //可输入字数
38 | @property (assign , nonatomic) NSInteger canEnterWordsNumber;
39 |
40 | @property (nonatomic, weak) id returnDelegate;
41 |
42 |
43 | //获取光标位置
44 | - (NSRange) selectedRange;
45 | //设置光标位置
46 | - (void) setSelectedRange:(NSRange) range;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/ZLYTextDemoUITests/ZLYTextDemoUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // ZLYTextDemoUITests.m
3 | // ZLYTextDemoUITests
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ZLYTextDemoUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation ZLYTextDemoUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/ZLYTextDemo/Assets.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 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/ZLYTextDemo/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 |
--------------------------------------------------------------------------------
/ZLYTextDemo/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 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ZLYTextDemo/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 |
27 |
28 |
--------------------------------------------------------------------------------
/ZLYTextDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ZLYTextDemo
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // 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.
25 | // 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.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // 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.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // 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.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // 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.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/ZLYTextDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // ZLYTextDemo
4 | //
5 | // Created by DCJ on 15/11/3.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "ZLYTextField.h"
11 | #import "ZLYTextView.h"
12 |
13 | #define kTextFieldMaxLength 10
14 | #define kTextViewMaxLength 80
15 |
16 | @interface ViewController ()
17 |
18 | @property (nonatomic, strong) ZLYTextView * textView;
19 | @property (nonatomic, strong) ZLYTextField * textField;
20 | @property (nonatomic, strong) UILabel * numLabel;
21 |
22 | @end
23 |
24 | @implementation ViewController
25 |
26 | - (void)viewDidLoad {
27 | [super viewDidLoad];
28 | // Do any additional setup after loading the view, typically from a nib.
29 | [self createTextField];
30 | [self createTextView];
31 | }
32 |
33 | -(void)createTextField{
34 | ZLYTextField * textField = [[ZLYTextField alloc]initWithFrame:CGRectMake(10, 20, self.view.frame.size.width-20, 40)];
35 | textField.borderStyle = UITextBorderStyleNone;
36 | textField.backgroundColor = [UIColor whiteColor];
37 | textField.layer.borderWidth = 1;
38 | textField.layer.borderColor = [UIColor colorWithWhite:219/255.0 alpha:1].CGColor;
39 | textField.returnKeyType = UIReturnKeyDone;
40 | textField.clearButtonMode = UITextFieldViewModeAlways;
41 | textField.MaxWordNumber = kTextFieldMaxLength;
42 | textField.LimiType = UnableToEnter;
43 | textField.returnDelegate = self;
44 |
45 | //不让文字左对齐
46 | UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 40)];
47 | textField.leftView = paddingView;
48 | textField.leftViewMode = UITextFieldViewModeAlways;
49 | [self.view addSubview:textField];
50 | _textField = textField;
51 | }
52 |
53 | -(void)createTextView
54 | {
55 | ZLYTextView * textView = [[ZLYTextView alloc]initWithFrame:CGRectMake(10, 80, self.view.frame.size.width-20, 150)];
56 | textView.font = [UIFont systemFontOfSize:17];
57 | textView.layer.borderWidth = 1;
58 | textView.textColor = [UIColor colorWithWhite:128/255.0 alpha:1];
59 | textView.layer.borderColor = [UIColor colorWithWhite:219/255.0 alpha:1].CGColor;
60 | textView.returnKeyType = UIReturnKeyDone;
61 | textView.MaxWordNumber = kTextViewMaxLength;
62 | textView.returnDelegate = self;
63 | textView.LimiType = UnableToEnter;
64 | [self.view addSubview:textView];
65 |
66 | _textView = textView;
67 |
68 | UILabel * label = [[UILabel alloc]init];
69 | label.translatesAutoresizingMaskIntoConstraints = NO;
70 | label.textAlignment = NSTextAlignmentCenter;
71 | NSInteger count = kTextViewMaxLength-textView.text.length;
72 | NSInteger num = count>0?count:0;
73 | label.text = [NSString stringWithFormat:@"%ld",(long)num];
74 | label.font = [UIFont systemFontOfSize:15];
75 | [self.view addSubview:label];
76 | _numLabel = label;
77 | NSLayoutConstraint * constraint1 = [NSLayoutConstraint constraintWithItem:_numLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_textView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
78 | NSLayoutConstraint * constraint2 = [NSLayoutConstraint constraintWithItem:_numLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_textView attribute:NSLayoutAttributeRight multiplier:1 constant:0];
79 | NSLayoutConstraint * constraint3 = [NSLayoutConstraint constraintWithItem:_numLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:30];
80 | NSLayoutConstraint * constraint4 = [NSLayoutConstraint constraintWithItem:_numLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:30];
81 | [self.view addConstraints:[NSArray arrayWithObjects:constraint1,constraint2,constraint3,constraint4, nil]];
82 | }
83 |
84 | -(void)rightBtnPress{
85 |
86 | }
87 |
88 | #pragma mark - ZLYTextFieldDelegate,ZLYTextViewDelegate
89 | -(void)textFieldReturnKeyPress:(ZLYTextField *)textField
90 | {
91 | [self rightBtnPress];
92 | }
93 |
94 | -(void)textViewReturnKeyPress:(ZLYTextView *)textView
95 | {
96 | [self rightBtnPress];
97 | }
98 |
99 | -(void)lwTextViewDidChange:(ZLYTextView *)textView
100 | {
101 | _numLabel.text = [NSString stringWithFormat:@"%ld",(long)textView.canEnterWordsNumber];
102 | }
103 |
104 |
105 |
106 | - (void)didReceiveMemoryWarning {
107 | [super didReceiveMemoryWarning];
108 | // Dispose of any resources that can be recreated.
109 | }
110 |
111 | @end
112 |
--------------------------------------------------------------------------------
/ZLYTextDemo.xcodeproj/xcuserdata/GL.xcuserdatad/xcschemes/ZLYTextDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/ZLYTextDemo/ZLYTextField.m:
--------------------------------------------------------------------------------
1 | //
2 | // WordlimitTextField.m
3 | // TextFieldExtesion
4 | //
5 | // Created by zly on 15/10/29.
6 | // Copyright © 2015年 Zhuluyi. All rights reserved.
7 | //
8 |
9 | #import "ZLYTextField.h"
10 |
11 | #define OSVersionIsAtLeastiOS7 (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
12 |
13 |
14 | @interface ZLYTextField ()
15 |
16 | @property (copy , nonatomic) NSString * lastString;
17 | @property (assign , nonatomic) BOOL isFirst;
18 |
19 | @end
20 |
21 |
22 | @implementation ZLYTextField
23 |
24 | //初始化及释放
25 | - (id)init{
26 | self = [super init];
27 | if (self) {
28 | [self addTextChangeObserver];
29 | }
30 | return self;
31 | }
32 |
33 | - (id)initWithCoder:(NSCoder *)aDecoder{
34 | self = [super initWithCoder:aDecoder];
35 | if (self) {
36 | [self addTextChangeObserver];
37 | }
38 | return self;
39 | }
40 |
41 | - (id)initWithFrame:(CGRect)frame{
42 | self = [super initWithFrame:frame];
43 | if (self) {
44 | [self addTextChangeObserver];
45 | }
46 | return self;
47 | }
48 |
49 | - (void)dealloc{
50 | [self removeTextChangeObserver];
51 | }
52 |
53 | //添加移除输入内容变化的监听事件
54 | - (void)addTextChangeObserver{
55 | self.isEmoticons = NO;
56 | self.LimiType = 1;
57 | self.textPoint = CGPointMake(8, 8);
58 | self.delegate = self;
59 | self.isFirst = YES;
60 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name: UITextFieldTextDidChangeNotification object:self];
61 | }
62 |
63 | - (void)removeTextChangeObserver{
64 | [[NSNotificationCenter defaultCenter] removeObserver:self];
65 | }
66 |
67 | //绘制方法
68 | - (void)drawRect:(CGRect)rect{
69 | [super drawRect:rect];
70 | CGContextRef context = UIGraphicsGetCurrentContext();
71 | if (self.text && self.text.length == 0){
72 | CGRect rect = CGRectMake(self.textPoint.x,
73 | self.textPoint.y,
74 | self.bounds.size.width - self.textPoint.x,
75 | self.bounds.size.height - self.textPoint.y);
76 | if (OSVersionIsAtLeastiOS7){
77 | NSDictionary* attributes = @{NSFontAttributeName:self.font,NSForegroundColorAttributeName:self.textColor};
78 | [self.text drawInRect:rect withAttributes:attributes];
79 | }
80 | else{
81 | CGContextSetFillColorWithColor(context, self.textColor.CGColor);
82 | #pragma clang diagnostic push
83 | #pragma clang diagnostic ignored "-Wdeprecated"
84 | [self.text drawInRect:rect withFont:self.font lineBreakMode:NSLineBreakByCharWrapping];
85 | #pragma clang diagnostic pop
86 | }
87 | }
88 | }
89 |
90 |
91 | #pragma mark - Set Method
92 |
93 | - (void)setText:(NSString *)text{
94 | [super setText:text];
95 | if (self.isFirst && !self.lastString) {
96 | self.isFirst = NO;
97 | self.lastString = text;
98 | }
99 | [self textChanged:nil];
100 | }
101 |
102 | -(void)setTextPoint:(CGPoint)textPoint{
103 | _textPoint = textPoint;
104 | [self setNeedsDisplay];
105 | }
106 |
107 | - (void)textChanged:(NSNotification *)notification{
108 | if (!notification) {
109 | return;
110 | }
111 | if (self.text.length != 0){
112 | [self setNeedsDisplay];
113 | }
114 | if(self.MaxWordNumber>0){
115 | NSString *toBeString = self.text;
116 | NSString *lang = [[[UIApplication sharedApplication] textInputMode] primaryLanguage];// 键盘输入模式
117 | if([lang isEqualToString:@"zh-Hans"]) { //简体中文输入,包括简体拼音,健体五笔,简体手写
118 | UITextRange *selectedRange = [self markedTextRange];
119 | //获取高亮部分
120 | UITextPosition *position = [self positionFromPosition:selectedRange.start offset:0];
121 | //没有高亮选择的字,则对已输入的文字进行字数统计和限制
122 | if(!position) {
123 | if (!self.isEmoticons){
124 | [self setDeleteEmojiText];
125 | }
126 | if(toBeString.length > self.MaxWordNumber) {
127 | switch (self.LimiType) {
128 | case 0:
129 | self.text = [self.text substringToIndex:self.MaxWordNumber];
130 | break;
131 | case 1:
132 | [self setLastText];
133 | break;
134 | default:
135 | break;
136 | }
137 | }
138 | self.lastString = self.text;
139 | }
140 | //有高亮选择的字符串,则暂不对文字进行统计和限制
141 | else{
142 | return;
143 | }
144 | }
145 | //中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
146 | else{
147 | if (!self.isEmoticons){
148 | [self setDeleteEmojiText];
149 | }
150 | if(toBeString.length > self.MaxWordNumber) {
151 | switch (self.LimiType) {
152 | case 0:
153 | self.text = [self.text substringToIndex:self.MaxWordNumber];
154 | break;
155 | case 1:
156 | [self setLastText];
157 | break;
158 | default:
159 | break;
160 | }
161 | }
162 | self.lastString = self.text;
163 | }
164 | }
165 | _canEnterWordsNumber = self.MaxWordNumber-self.text.length;
166 | _canEnterWordsNumber = _canEnterWordsNumber>0?_canEnterWordsNumber:0;
167 | }
168 |
169 | -(void)setLastText{
170 | UITextPosition* beginning = self.beginningOfDocument;
171 | UITextRange* selectedRange = self.selectedTextRange;
172 | UITextPosition* selectionStart = selectedRange.start;
173 | UITextPosition* selectionEnd = selectedRange.end;
174 | const NSInteger location = [self offsetFromPosition:beginning toPosition:selectionStart];
175 | const NSInteger length = [self offsetFromPosition:selectionStart toPosition:selectionEnd];
176 | NSRange range = NSMakeRange(location-(self.text.length-self.lastString.length), length);
177 | self.text = self.lastString;
178 | beginning = self.beginningOfDocument;
179 | UITextPosition* startPosition = [self positionFromPosition:beginning offset:range.location];
180 | UITextPosition* endPosition = [self positionFromPosition:beginning offset:range.location + range.length];
181 | UITextRange* selectionRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
182 | [self setSelectedTextRange:selectionRange];
183 | }
184 |
185 | -(void)setDeleteEmojiText{
186 | UITextPosition* beginning = self.beginningOfDocument;
187 | UITextRange* selectedRange = self.selectedTextRange;
188 | UITextPosition* selectionStart = selectedRange.start;
189 | UITextPosition* selectionEnd = selectedRange.end;
190 | const NSInteger location = [self offsetFromPosition:beginning toPosition:selectionStart];
191 | const NSInteger length = [self offsetFromPosition:selectionStart toPosition:selectionEnd];
192 | NSRange range;
193 | if([[self deleteEmojiWithString:self.text] length] NSFoundationVersionNumber_iOS_6_1)
12 |
13 |
14 | @interface ZLYTextView ()
15 |
16 | @property (copy , nonatomic) NSString * lastString;
17 | @property (assign , nonatomic) BOOL isFirst;
18 |
19 | @end
20 |
21 |
22 | @implementation ZLYTextView
23 |
24 | //初始化及释放
25 | - (id)init{
26 | self = [super init];
27 | if (self) {
28 | [self addTextChangeObserver];
29 | }
30 | return self;
31 | }
32 |
33 | - (id)initWithCoder:(NSCoder *)aDecoder{
34 | self = [super initWithCoder:aDecoder];
35 | if (self) {
36 | [self addTextChangeObserver];
37 | }
38 | return self;
39 | }
40 |
41 | - (id)initWithFrame:(CGRect)frame{
42 | self = [super initWithFrame:frame];
43 | if (self) {
44 | [self addTextChangeObserver];
45 | }
46 | return self;
47 | }
48 |
49 | - (void)dealloc{
50 | [self removeTextChangeObserver];
51 | }
52 |
53 | //添加移除输入内容变化的监听事件
54 | - (void)addTextChangeObserver{
55 | self.LimiType = 1;
56 | self.isEmoticons = NO;
57 | self.textPoint = CGPointMake(8, 8);
58 | self.delegate = self;
59 | self.isFirst = YES;
60 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textChanged:) name:UITextViewTextDidChangeNotification object:self];
61 | }
62 |
63 | - (void)removeTextChangeObserver{
64 | [[NSNotificationCenter defaultCenter] removeObserver:self];
65 | }
66 |
67 | //绘制方法
68 | - (void)drawRect:(CGRect)rect{
69 | [super drawRect:rect];
70 | CGContextRef context = UIGraphicsGetCurrentContext();
71 | if (self.text && self.text.length > 0 && self.text.length == 0){
72 | CGRect rect = CGRectMake(self.textPoint.x,
73 | self.textPoint.y,
74 | self.bounds.size.width - self.textPoint.x,
75 | self.bounds.size.height - self.textPoint.y);
76 | if (OSVersionIsAtLeastiOS7){
77 | NSDictionary* attributes = @{NSFontAttributeName:self.font,NSForegroundColorAttributeName:self.textColor};
78 | [self.text drawInRect:rect withAttributes:attributes];
79 | }
80 | else{
81 | CGContextSetFillColorWithColor(context, self.textColor.CGColor);
82 | #pragma clang diagnostic push
83 | #pragma clang diagnostic ignored "-Wdeprecated"
84 | [self.text drawInRect:rect withFont:self.font lineBreakMode:NSLineBreakByCharWrapping];
85 | #pragma clang diagnostic pop
86 | }
87 | }
88 | }
89 |
90 | #pragma mark - Set Method
91 |
92 | - (void)setText:(NSString *)text{
93 | [super setText:text];
94 | if (self.isFirst && !self.lastString) {
95 | self.isFirst = NO;
96 | self.lastString = text;
97 | }
98 | [self textChanged:nil];
99 | }
100 |
101 | -(void)setTextPoint:(CGPoint)textPoint{
102 | _textPoint = textPoint;
103 | [self setNeedsDisplay];
104 | }
105 |
106 | - (void)textChanged:(NSNotification *)notification{
107 | if (!notification) {
108 | return;
109 | }
110 | if (self.text.length != 0){
111 | [self setNeedsDisplay];
112 | }
113 | if(self.MaxWordNumber>0){
114 | NSString *toBeString = self.text;
115 | NSString *lang = [[[UIApplication sharedApplication] textInputMode] primaryLanguage];// 键盘输入模式
116 | if([lang isEqualToString:@"zh-Hans"]) { //简体中文输入,包括简体拼音,健体五笔,简体手写
117 | UITextRange *selectedRange = [self markedTextRange];
118 | //获取高亮部分
119 | UITextPosition *position = [self positionFromPosition:selectedRange.start offset:0];
120 | //没有高亮选择的字,则对已输入的文字进行字数统计和限制
121 | if(!position) {
122 | if (!self.isEmoticons){
123 | [self setDeleteEmojiText];
124 | }
125 | if(toBeString.length > self.MaxWordNumber) {
126 | switch (self.LimiType) {
127 | case 0:
128 | self.text = [self.text substringToIndex:self.MaxWordNumber];
129 | break;
130 | case 1:
131 | [self setLastText];
132 | break;
133 | default:
134 | break;
135 | }
136 | }
137 | self.lastString = self.text;
138 | }
139 | //有高亮选择的字符串,则暂不对文字进行统计和限制
140 | else{
141 | return;
142 | }
143 | }
144 | //中文输入法以外的直接对其统计限制即可,不考虑其他语种情况
145 | else{
146 | if (!self.isEmoticons){
147 | [self setDeleteEmojiText];
148 | }
149 | if(toBeString.length > self.MaxWordNumber) {
150 | switch (self.LimiType) {
151 | case 0:
152 | self.text = [self.text substringToIndex:self.MaxWordNumber];
153 | break;
154 | case 1:
155 | [self setLastText];
156 | break;
157 | default:
158 | break;
159 | }
160 | }
161 | self.lastString = self.text;
162 | }
163 | }
164 |
165 | _canEnterWordsNumber = self.MaxWordNumber-self.text.length;
166 | _canEnterWordsNumber = _canEnterWordsNumber>0?_canEnterWordsNumber:0;
167 |
168 | if (self.returnDelegate&&[self.returnDelegate respondsToSelector:@selector(lwTextViewDidChange:)]) {
169 | [self.returnDelegate lwTextViewDidChange:self];
170 | }
171 | }
172 |
173 | -(void)setLastText{
174 | UITextPosition* beginning = self.beginningOfDocument;
175 | UITextRange* selectedRange = self.selectedTextRange;
176 | UITextPosition* selectionStart = selectedRange.start;
177 | UITextPosition* selectionEnd = selectedRange.end;
178 | const NSInteger location = [self offsetFromPosition:beginning toPosition:selectionStart];
179 | const NSInteger length = [self offsetFromPosition:selectionStart toPosition:selectionEnd];
180 | NSRange range = NSMakeRange(location-(self.text.length-self.lastString.length), length);
181 | self.text = self.lastString;
182 | beginning = self.beginningOfDocument;
183 | UITextPosition* startPosition = [self positionFromPosition:beginning offset:range.location];
184 | UITextPosition* endPosition = [self positionFromPosition:beginning offset:range.location + range.length];
185 | UITextRange* selectionRange = [self textRangeFromPosition:startPosition toPosition:endPosition];
186 | [self setSelectedTextRange:selectionRange];
187 | }
188 |
189 | -(void)setDeleteEmojiText{
190 | UITextPosition* beginning = self.beginningOfDocument;
191 | UITextRange* selectedRange = self.selectedTextRange;
192 | UITextPosition* selectionStart = selectedRange.start;
193 | UITextPosition* selectionEnd = selectedRange.end;
194 | const NSInteger location = [self offsetFromPosition:beginning toPosition:selectionStart];
195 | const NSInteger length = [self offsetFromPosition:selectionStart toPosition:selectionEnd];
196 | NSRange range;
197 | if([[self deleteEmojiWithString:self.text] length]