IOS 自动补全Email的TextField

本文介绍了一种自定义UITextField的方法,通过监听文本变化来实现在输入@符号后自动补全电子邮件地址的功能。提供了两种补全方式:弹出TableView供用户选择后缀或直接在文本框中显示灰色的邮件后缀。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Demo下载地址:http://download.youkuaiyun.com/detail/shengyumojian/8497381


项目中需要在textfield中输入@后自动补全email,于是自己写了一个支持补全email的TextField。主要支持两种方式补全:

1-在输入@后弹出tableview(样式比较粗糙,可自行扩张美化),供用户选择后缀。

2-在输入@后,在文本框后面直接显示email后缀(email后缀为灰色)。

先看看效果吧:

                 



来看看主要逻辑代码:


这就是是否需要自动补全email的属性,根据需要设置需要补全的方式

@property (nonatomic, assign) BOOL isShowEmailSuffix;   //是否在输入@后显示email后缀
@property (nonatomic, assign) BOOL isAutoCompleterEmailSuffix;  //是否自动补全email后缀

下面是初始化方法

#pragma mark - Lifecycle

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self initialize];
    }
    
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self initialize];
    }
    
    return self;
}

其中resetRightView是设置右边的clear按钮,可以自行考虑是否需要;重要的是添加通知的监听,可能有小伙伴会问为什么不使用textfield的协议(委托)来实现,而要选择用通知?因为在这里用通知就可以把协议(委托)的实现留给其它viewcontroller

//初始化
- (void)initialize
{
    [self addNotification];
    [self resetRightView];
}

//添加通知监听
- (void)addNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldTextDidChangeNotification:) name:UITextFieldTextDidChangeNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldTextDidEndEditingNotification:) name:UITextFieldTextDidEndEditingNotification object:self];
}

//重置右边按钮变为x
- (void)resetRightView
{
    UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 20, 20)];
    [myButton setImage:[UIImage imageNamed:@"com_txt_btn_clear"] forState:UIControlStateNormal];
    [myButton addTarget:self action:@selector(whenClearBtnTapped:) forControlEvents:UIControlEventTouchUpInside];
    myButton.userInteractionEnabled = YES;
    
    self.rightView = myButton;
    self.rightViewMode = UITextFieldViewModeWhileEditing;
    self.rightView.userInteractionEnabled = YES;
}


接下来是通知的实现,其中_isMarketHandle是为了兼容ios8下的中文输入法

#pragma mark ---------------------
#pragma mark - NSNotification

//通知:textfield文本改变时通知
- (void)textFieldTextDidChangeNotification:(NSNotification *)notification
{
    if (notification.object && notification.object != [NSNull null] && notification.object == self) {  //如果文本改变通知是自己
        
        if (_isMarketHandle) {
            _isMarketHandle = NO;
            return;
        }
        
        //如果在输入@后显示与文本有@符号,则显示
        if (self.isShowEmailSuffix && [self.text rangeOfString:@"@"].location != NSNotFound) {
            [self showSelectedEmailSuffix]; //显示
        } else {
            [self hideSelectedEmailSuffix]; //隐藏
        }
        
        //如果在输入@后显示与文本有@符号,则自动补全
        if (self.isAutoCompleterEmailSuffix) {
            if (self.color) {
                self.textColor = self.color;
            }
            if ([self.text rangeOfString:@"@"].location != NSNotFound) {
                [self showPlaceholderWithEmail];
            } else if (self.autoCompleterText) {
                self.text = [self.text stringByReplacingOccurrencesOfString:self.autoCompleterText withString:@""];
                self.autoCompleterText = nil;
            }
        }
        
    } else {
        [self hideSelectedEmailSuffix]; //隐藏
    }
}

//通知:textfield文本结束编辑时通知
- (void)textFieldTextDidEndEditingNotification:(NSNotification *)notification
{
    if (notification.object && notification.object != [NSNull null] && notification.object == self) {  //如果文本改变通知是自己
        if (self.isAutoCompleterEmailSuffix) {
            if (self.color) {
                self.textColor = self.color;
            }
            self.autoCompleterText = nil;
        }
    }
}


接下来看看tableview显示的代码,tableview内部实现在此不多说,可以把代码下载来看看


//显示选择email后缀
- (void)showSelectedEmailSuffix
{
    if (self.emailSuffixView) {
        [self.emailSuffixView hide];
        self.emailSuffixView = nil;
    }
    
    self.emailSuffixView = [[KBSelectedEmailSuffixView alloc] initWithTargerView:self withDelegate:self withCurrentText:self.text];
    [self.emailSuffixView show];
}

//隐藏选择email后缀
- (void)hideSelectedEmailSuffix
{
    if (self.emailSuffixView) {
        [self.emailSuffixView hide];
        self.emailSuffixView = nil;
    }
}


再来看看第二种方式,在文本后显示email后缀。为了兼容ios8下的中文输入法,我们需要判断textinput是否有markedText;而在ios7下,无论是中文还是英文输入法,都可以使用selectedTextRange。

//提示email
- (void)showPlaceholderWithEmail
{
    /*markedTextRange 和 selectedTextRange 是不同的 ,markedTextRange是高亮文字(比如中文输入法输入文字后的显示)  selectedTextRange是选中的文字*/
    UITextRange *range = nil;
    if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 8.0) {  //ios8系统下才需要判读,因为在ios8下才不正常
        range = self.markedTextRange ? self.markedTextRange : self.selectedTextRange; //markedTextRange有高亮一段文字才有值,selectedTextRange的值都是在光标末尾
    } else {
        range = self.selectedTextRange;
    }
    UITextPosition *startTextPosition = range.start;
    UITextPosition *endTextPosition = range.end;
    NSInteger startPosition = [[startTextPosition valueForKey:@"offset"] integerValue];   //当前光标的开始位置
    NSInteger endPosition = [[endTextPosition valueForKey:@"offset"] integerValue];   //当前光标的结束位置
    
    NSString *language = [[UITextInputMode currentInputMode] primaryLanguage]; // 键盘输入模式
    
    BOOL isChineseLanguage = [language isEqualToString:@"zh-Hans"]; //是否是简体中文输入,包括简体拼音,健体五笔,简体手写
    if (isChineseLanguage &&
        startPosition != endPosition
        && !self.autoCompleterText) {    //如果在简体中文下有高亮文字范围,且当前没匹配过email,则跳出
        return;
    }
    
    //如果有高亮文字范围,且后面有文字,把高亮后的文字去掉
    if (startPosition != endPosition && self.text.length > endPosition) {
        self.text = [self.text substringToIndex:startPosition];
        _isMarketHandle = YES;
        [self setMarkedText:_perviousMarketText selectedRange:_perviousSelectedRange];
        return;
    } else if (startPosition != endPosition) {  //如果有高亮文字 且 高亮文字后面没文字了,则跳出
        return;
    }
    
    NSString *currentInputSuffix = nil;
    NSString *postionText = [self.text substringToIndex:endPosition];
    
    if ([postionText rangeOfString:@"@"].location == NSNotFound) {
        currentInputSuffix = nil;
    } else {
        NSInteger location = [postionText rangeOfString:@"@"].location + 1;
        if (postionText.length <= location) {
            currentInputSuffix = nil;
        } else {
            currentInputSuffix = [NSString stringWithFormat:@"%@",[postionText substringFromIndex:location]];
        }
    }
    
    
    //后缀
    NSMutableArray *arraySuffix = [kKBTextFieldEmailSuffix mutableCopy];
    
    //移除不包含现在输入过的后缀的邮箱后缀
    NSIndexSet *indexSet = [arraySuffix indexesOfObjectsWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
        
        NSString *suffix = obj;
        //如果当前输入的后缀为空或递归到的后缀包含当前输入的后缀,则不被移除
        if (!currentInputSuffix || [currentInputSuffix isEqualToString:@""] || [suffix rangeOfString:currentInputSuffix].location == 0) {
            return NO;
        } else {
            return YES;
        }
    }];
    [arraySuffix removeObjectsAtIndexes:indexSet];
    
    if (arraySuffix.count > 0) {
        self.text = [NSString stringWithFormat:@"%@%@",[self.text substringToIndex:[self.text rangeOfString:@"@"].location + 1], arraySuffix[0]];   //重置text

        //设置富文本属性
        if (!self.color) {
            self.color = [self.textColor copy];
        }
        
        NSMutableAttributedString *attributedStringOrder = [[NSMutableAttributedString alloc] initWithString:self.text];
        [attributedStringOrder addAttribute:NSForegroundColorAttributeName
                                      value:self.color
                                      range:NSMakeRange(0, endPosition)];
        NSRange autoCompleterTextRange = NSMakeRange(endPosition, self.text.length - endPosition);
        self.autoCompleterText = [self.text substringWithRange:autoCompleterTextRange];
        [attributedStringOrder addAttribute:NSForegroundColorAttributeName
                                      value:YYColor(188.0, 188.0, 188.0)
                                      range:autoCompleterTextRange];
        self.attributedText = attributedStringOrder;
        
        //移动光标位置
        if (endPosition  < self.text.length) {
            NSInteger offset = self.text.length - (endPosition );
            [self moveCursor:self inDirection:UITextLayoutDirectionLeft offset:offset];
        }
    } else {
        self.text = [self.text substringToIndex:endPosition];

        self.autoCompleterText = nil;
    }
}

最后,我们需要在- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange中记录一下当前markedText和selectedRnage

- (void)setMarkedText:(NSString *)markedText selectedRange:(NSRange)selectedRange
{
    _perviousMarketText = markedText;
    _perviousSelectedRange = selectedRange;
    @try {
        [super setMarkedText:markedText selectedRange:selectedRange];
    }
    @catch (NSException *exception) {
        NSLog(@"error: setMarkedText:selectedRange");
    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值