很遗憾,此处发布的解决方案不适用于具有复合字符的语言(如韩语)。
像韩语(Hangul)这样的语言有一个复合字符,其中每个字母由多个符号组成。比如‘ㅁ’、‘ㅏ’和‘ㄴ’都是单独的字符,但是组合起来就变成了‘만’,被当作一个字母来处理。
这是适用于所有语言的解决方案。
在 UITextField 上放置一个 UILabel。将 UILabel 的框架设置为比 UITextField 略小,使其位于 UITextField 内,但仍会遮挡 UITextField 的文本。 textField: shouldChangeCharactersInRange:withReplacementString 在文本完成之前被调用。这意味着我们需要自己完成文本。这对于像韩语这样的复合字符语言更难做到。相反,注册 UITextFieldTextDidChangeNotification,它将在新文本出现在 UITextField 上后调用。
@interface MKSecureTextField()<UITextFieldDelegate>
@property (nonatomic, strong) UITextField* textField;
@property (nonatomic, strong) UILabel* hideLabel;
@property (nonatomic, strong) NSTimer* hideTimer;
@property (nonatomic, strong) NSTimer* blinkTimer;
@end
@implementation MKSecureTextField
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
_textField.userInteractionEnabled = YES;
_textField.borderStyle = UITextBorderStyleRoundedRect;
_textField.font = [UIFont systemFontOfSize:14];
_textField.placeholder = @"enter text";
_textField.autocorrectionType = UITextAutocorrectionTypeNo;
_textField.keyboardType = UIKeyboardTypeDefault;
_textField.returnKeyType = UIReturnKeyDone;
_textField.clearButtonMode = UITextFieldViewModeWhileEditing;
_textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
_textField.delegate = self;
self.hideLabel = [[UILabel alloc] initWithFrame:CGRectMake(6, 5, frame.size.width-10, frame.size.height-12)];
_hideLabel.backgroundColor = [UIColor whiteColor];
[self addSubview:_textField];
[self addSubview:_hideLabel];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldDidChange:) name:UITextFieldTextDidChangeNotification object:nil];
}
return self;
}
当收到 UITextFieldTextDidChangeNotification 时,隐藏除最后一个字符之外的所有字符。隐藏文本将以编程方式在 UILabel 上设置。此外,安排一个将隐藏最后一个字符的计时器。如果键入更多文本,则此计时器无效。
- (void)textFieldDidChange:(NSNotification*)notification
{
UITextField* textField = notification.object;
if (textField == _textField)
{
NSString* text = textField.text;
[self hideExceptLastCharacter:text];
[self.hideTimer invalidate];
self.hideTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(hideLastCharacter)
userInfo:nil
repeats:NO];
}
}
UILabel 没有闪烁的光标。所以我们通过在'|'之间交替来模拟它和一个空间。闪烁的光标在编辑开始时放置,在编辑结束时移除。
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
if (_hideLabel.text == nil)
{
_hideLabel.text = @"|";
}
else
{
_hideLabel.text = [_hideLabel.text stringByAppendingString:@"|"];
}
self.blinkTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(blinkCursor) userInfo:nil repeats:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
NSRange range;
range.location = _hideLabel.text.length - 1;
range.length = 1;
_hideLabel.text = [_hideLabel.text stringByReplacingCharactersInRange:range withString:@""];
[_blinkTimer invalidate];
}
- (void)blinkCursor
{
if (_hideLabel.text.length > 0)
{
static BOOL visible = YES;
NSRange range;
range.location = _hideLabel.text.length - 1;
range.length = 1;
if (visible)
{
_hideLabel.text = [_hideLabel.text stringByReplacingCharactersInRange:range withString:@" "];
}
else
{
_hideLabel.text = [_hideLabel.text stringByReplacingCharactersInRange:range withString:@"|"];
}
visible = !visible;
}
}
除了最后一个字符之外的字符被隐藏。这是在 UILabel 上设置的。 UITextField 保持不变。
- (void)hideExceptLastCharacter:(NSString*)string
{
int length = [_textField.text length];
NSString* s = @"";
for (int i = 0; i < length-1; i++)
{
s = [s stringByAppendingString:@"●"];
}
if (_textField.text.length > 0)
{
_hideLabel.text = [s stringByAppendingString:[_textField.text substringFromIndex:_textField.text.length-1]];
_hideLabel.text = [_hideLabel.text stringByAppendingString:@"|"];
}
else
{
_hideLabel.text = @"|";
}
}
- (void)hideLastCharacter
{
if (_hideLabel.text.length > 1)
{
NSRange range;
range.location = [_hideLabel.text length]-2;
range.length = 1;
_hideLabel.text = [_hideLabel.text stringByReplacingCharactersInRange:range withString:@"●"];
}
}
- (void)dealloc
{
[_hideTimer invalidate];
[_blinkTimer invalidate];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end
请参阅此Github project 以供参考。