├── 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]