转载

简单易用 的 iOS 分类 UITextView & UITextField & UIControl & NSStrin

标题显得很屌丝,搞那么长、长就长一点吧,这样可能方便搜索。

一、先看一张图

简单易用 的 iOS 分类 UITextView & UITextField & UIControl & NSStrin

神气的 iOS 分类

是的、就这三个分类:NSString+Regex,UITextField+HG,UITextView+HG。接下来就对他们做一个简单的介绍。

二、如何获取

在之前、已经放到 pod 上。所以获取方式有两种:

1、直接到这里Categorys去查看。

2、通过 pod 方式拉取:

pod 'HGCategorys'

温馨提示:一般 Podfile 应该如何去创建?很多同行是这样的命令:vim Podfile,其实最专业&方便的创建姿势是这样的:pod init 。

看了代码之后会发现实现是很简单的,不仅代码简单、功能也很简单。存在、就是真理。再简单、也一起看一看有何用途吧。

三、有何功能

1、NSString+Regex

先看分类名 Regex,正则表达式的意思。那么这部分的功能就很明确了,主要就是一个字符串的匹配。在开发的过程中对 正则表达式 的使用几乎是不难的,但是如何将不同的功能整合在一起,这恐怕是一个问题。接下来看一看这里面到底是如何实现的(只看.h 文件中的内容)。

1.1 枚举定义

具体定义如下:

// 基本匹配 : 数字, 汉字, 字符, 空格, 下划线, 点, @
typedef NS_OPTIONS(NSUInteger, HGRegexType) {
    HGRegexTypeNone      = 0 << 0, // 未知
    HGRegexTypeDigital   = 1 << 0, // 数字
    HGRegexTypeChinese   = 1 << 1, // 汉字
    HGRegexTypeCharacter = 1 << 2, // 字符
    HGRegexTypeSpace     = 1 << 3, // 空格
    HGRegexTypeUnderline = 1 << 4, // 下划线
    HGRegexTypeDot       = 1 << 5, // 点
    HGRegexTypeAT        = 1 << 6, // @
};

关于这个枚举的定义的一大亮点就是 NS_OPTIONS,千万不要看成 NS_ENUM,这两种枚举在用法上是有很大区别的。相比较而言 NS_OPTIONS 的功能比 NS_ENUM 还要强大。这里并不说我现在使用了 NS_OPTIONS 就吹嘘它强大,而显得自己有多牛逼。不是这样的、而是想说,对于OC 中的枚举一定要弄清楚这两种的不同。在适当的时机使用适当的实现方式,才能让自己的代码更加合理、更加牛气。

其实苹果给我们提供了很多这样的枚举,比如 UIViewAutoresizingNSKeyValueObservingOptions 等等。

看到这里,应该能猜测到 HGRegexType 的用途是什么了。我不说、你不说,心里知道就可以了。[偷笑 5 秒钟、思考一小时]

1.2 提供的方法

在上代码之前,先自我批评一下:所有的方法注释,没有对参数做介绍。这是在写代码过程中的大忌,在 .m 文件中可以不用、但是在 .h 文件中不做注释,这肯定是不对的。由于代码是3个月前上传的,也不想去更新了。

直接看代码:

/**
 * 通过 pattern 进行匹配
 */
- (BOOL)hg_regexMatchWithPattern:(NSString*)pattern;

/**
 * 基本匹配: 是否支持空字符串返回为YES的情况
 */
- (BOOL)hg_regexMatchWithType:(HGRegexType)rType returnWhenEmpty:(BOOL)empty;

看过代码的你应该知道,实际提供的方法不止以上的两个。但是没有关系,只要明白了这两个方法,其它方法看到就秒懂了。接下来细说一下这两个方法。

/**
 * 通过 pattern 进行匹配
 */
- (BOOL)hg_regexMatchWithPattern:(NSString*)pattern;

当你看到这个方法,根据你多年的开发经验,再加上我那么屌丝的注释,你可能会这样的去用:

// 匹配的条件
NSString* pattern = @".";
// 即将匹配的字符串
NSString* strTEXT = @"CoderHG.";
// 匹配结果
BOOL result = [hg_regexMatchWithPattern:pattern];

// 打印
if (result) {
    NSLog(@"有点");
} else {
    NSLog(@"没点");
}

毫无保留的认为 strTEXT 中有一个点(.),所以结果 result 的值是 YES,打印的是 有点。其实不是这样,这里的结果是 NO。我的这个方法的意思是要 完全匹配 才算 YES,因为我之前设计这个匹配功能的初衷是:一个字符串中只能只包含 pattern 中的字符,如果多了,就算失败。

所以、以上如果想要让 strTEXT 完全匹配成功,只能是将 pattern 改成这样 ^[a-zA-Z.]+$,意思是 strTEXT 中只能出现字符与点(.)的情况下才能成功,多了,都是失败。显然 strTEXT 中除了点(.)还有其它,所以为 NO

这样的功能,一般用于什么样的地方呢?比较常用的地方就是,密码验证。往往会有这样的要求:有且只能用字符、数字与下划线。所以就可以弄弄成这样的:

// 匹配的条件
NSString* pattern = @"^[//da-zA-Z_]+$";
// 即将匹配的字符串
NSString* strTEXT = @"CoderHG123";
// 匹配结果
BOOL result = [strTEXT hg_regexMatchWithPattern:pattern];

// 打印
if (result) {
    NSLog(@"%@ 中只包含数字,字符与下划线", strTEXT);
} else {
    NSLog(@"%@ 中除了包含数字,字符与下划线,还有其它字符", strTEXT);
}

如果 strTEXT 中还包含了 数字,字符与下划线 之外的字符,那么就返回 NO

那么问题又来了,每次都要去写 pattern 这样的正则表达式,还麻烦啊。是的,的确是很麻烦的。接下来看另外一个方法。

/**
 * 基本匹配: 是否支持空字符串返回为YES的情况
 */
- (BOOL)hg_regexMatchWithType:(HGRegexType)rType returnWhenEmpty:(BOOL)empty;

这个方法中,终于使用上那个枚举(HGRegexType)了,看了上的所有解释,应该都知道这个 rType 如何传值了。但是后面的 empty 是怎么回事么?主要是为了处理给空字符串(@"")而准备的。如果是空字符串(@"")的话,是算匹配成功还是匹配失败呢。主要还是要看心情,不对、主要还是要看需求。 empty 传什么,在如果是空字符串(@"")的时候就返回什么。

那么我们就可以来用一下了,如果一个需求是这样的:一个字符串只能包含字母、数字与下划线,并且如果当前字符串为空(@"")的时候,返回为 YES。那么就可以这样弄了:

// 即将匹配的字符串
NSString* strTEXT = @"CoderHG123";

// 匹配的条件 数字 | 字母 | 下划线
HGRegexType rType = HGRegexTypeDigital | HGRegexTypeCharacter | HGRegexTypeUnderline;
// 匹配结果
BOOL result = [strTEXT hg_regexMatchWithType:rType returnWhenEmpty:YES];

// 打印
if (result) {
    NSLog(@"%@ 中只包含数字,字符与下划线", strTEXT);
} else {
    NSLog(@"%@ 中除了包含数字,字符与下划线,还有其它字符", strTEXT);
}

这样看起来,就清晰了很多。到现在为止,NSString+Regex 部分就介绍结束了,希望能对你有所帮助。

欲知更多精彩,请看下面分解。

2、UITextField+HG

这部分不做介绍,功能与 UITextView+HG 类似,直接看 UITextView+HG 即可。

3、UITextView+HG

其实对于文本框的输入,是有很多的话要说的,但是接下来要介绍的仅仅是其中的冰山一角。当遇到输入文本时,还需要有文字限制的时候,应该如何去处理。比如现在的微信(现在的版本号是6.6.5)的个性签名只能输入30个字符,多一个就不行。像我的个性签名是这样的:

简单易用 的 iOS 分类 UITextView & UITextField & UIControl & NSStrin

Later equals never.

一看我的个性签名,我感觉确实很有个性的。微信只让最多输入30个字符,我就不多也不少的弄30个。其中 升值 的意思是: 努力提升自己的价值。

但是如果我现在想将 感谢自己! 换成感谢所有人,那么是修改不成功的,因为微信根本就输入不进去了。这说明什么呢??[郁闷3秒钟、思考几十年]

简单易用 的 iOS 分类 UITextView & UITextField & UIControl & NSStrin

不能感谢所有人、只能感谢自己!

现在总结一下微信个性签名的文字限制的一个特点:在输入还处于高亮的时候,就已经开始计算字符。导致在最后无法输入想要输入的结果。

如果说一定要感谢所有人, 应该这么处理呢?目的就是要打破上面的那一个特点:在输入的过程中,高亮的部分不参与字符计算。于是 UITextView+HG 就诞生了。

关于这个 分类,实现是很简单的。如果要完全的实现 在输入的过程中,高亮的部分不参与字符计算。还需要其它的处理。现在先来看一下这个分类都做了什么处理。主要就一个属性与一个方法:

/** 是否高亮 */
@property (nonatomic, readonly) BOOL hg_isHighLighted;


/**
 输入无效,将已经数据的打回原形
 
 @param curContent 希望当前的显示内容
 */
- (void)hg_invalidTextFieldCurContent:(NSString*)curContent;

hg_isHighLighted 诸葛属性主要是用来判断当前的输入框是否在处于高亮的状态。

重点是下面的方法:

注释中的 输入无效,将已经数据的打回原形,当输入超出限制的时候,将高亮的部分去掉去掉,回到高亮之前的状态。这个方法中不仅处理了在文本的最后输入的情况,主要是处理了在文本的中间部分输入的情况下。光标不会跑到最后,而是在高亮的上一个位置。听起来很高大上,同时也很模糊。可以到 HGCategorysDemo 目录中找到具体的项目代码,这个代码最好是:pod update 一下。

具体的功能是在 SetupSignatureCell 中实现的,发现这里面的代码不少,主要是一些代理与数字的控制。与之相关的代码,在这里:

#pragma mark -
#pragma mark - UITextViewDelegate
- (void)textViewDidChange:(UITextView *)textView {
    // 必须要在这里弄.
    self.placeholderLabel.hidden = (textView.text.length > 0);;
    
    // 如果在变化中是高亮部分在变,就不要计算字符了
    if (textView.hg_isHighLighted) {
        return ;
    }
    
    // 主要是处理当输入超出限制时的优化
    if (textView.text.length > self.maxCount) {
        [textView hg_invalidTextFieldCurContent:_signatureTEXT];
    }
    
    // 代理
    if (self.delegate && [self.delegate respondsToSelector:@selector(setupSignatureCell:didChangedValue:)]) {
        [self.delegate setupSignatureCell:self didChangedValue:textView.text];
    }
    
    // 保留
    // 不能这么调用
//    self.signatureTEXT = textView.text;
    
    // 正确的姿势是这样的
    _signatureTEXT = textView.text;
    _countLabel.text = [NSString stringWithFormat:@"%zd/%zd", self.signatureTEXT.length, (self.maxCount - self.signatureTEXT.length)];
}

是的,没有错,仅仅是在一个地方用到。其中,值得注意的是 signatureTEXT 这个属性是必不可少的。如果没有,那么光标的问题很难处理。现在感兴趣的话,就可以慢慢的看这个SetupSignatureCell 中实现。到此为止,UITextView+HG 的介绍以及一个个性签名的实现基本上结束了。

4、说点题外话

对于 UITextField ,大家尽量不要去使用通知来控制各种状态,最好是使用代理与事件。别忘了UITextField是继承于 UIControl 的。在 UITextView 的delegate 中有 textViewDidChange: 这样的代理方法,但是在 UITextField 中却是没有的,我们可以通过UIControlEventEditingChanged来添加事件。如:

[textField addTarget:self  action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];

// 文本变化
- (void)textFieldDidChange:(UITextField *)textField
{
    // TODO:
}

四、说在最后的话

本来打算上午就弄完的,没想到搞到了现在。感谢阅读的你、也感谢自己!

以上的功能,不值一提,都是冰山一角。不积跬步无以至千里,我们一步一步的来。

如果由于刚刚时间仓促,忘记了下拉代码,那么可以直接点击这里点击这里点击这里。关于个性签名的代码,记得到 HGCategorysDemo 目录的查看。

要是有什么不对的、或者需要补充的,感谢评论讨论!

我的更多文章,可以直接看这里NewStart NewStart NewStart

谢谢大家!

你说得很对,但是没有意义。-- 来自 《职来职往》

作者:CoderHG

链接:https://www.jianshu.com/p/d3a3242f50e6

正文到此结束
Loading...