最項目有一個提現(xiàn)的功能掂恕,像支付寶拖陆、微信輸入支付密碼樣式的文本框,這樣的輪子已經(jīng)很多了竹海,用起來都不太適合自己慕蔚,所以決定自己去重復(fù)造個,大多數(shù)的實現(xiàn)方式都用一個View 又放上一個UITextField斋配,只是這個TextField 看不到孔飒,不太喜歡這種實現(xiàn)方式那有沒有更好的方式呢?那就本文的重點想說的UIKeyInput, 這個protocol 很簡單只有三個方法
@protocol UIKeyInput <UITextInputTraits>
- (BOOL)hasText;// A Boolean value that indicates whether the text-entry objects has any text. (required)YES
//if the backing store has textual content, NO otherwise. 官方文檔的解釋我也翻譯不好
- (void)insertText:(NSString *)text;// 插入文本
- (void)deleteBackward; // 鍵盤上的退格事件
@end
實現(xiàn)了這個協(xié)議我們就可以實現(xiàn)一個簡單文本輸入視圖了艰争,先看看實現(xiàn)的最終效果:
代碼很簡單實現(xiàn)的這個三個協(xié)議坏瞄,就可以接受鍵盤的一些輸入了,還有一個協(xié)議我們也需要看下就是我們在使用textField 經(jīng)常用的一些東西甩卓,那就是 :UITextInputTraits 看起很陌生鸠匀,我們點進(jìn)去看看源碼:
@protocol UITextInputTraits <NSObject>
@optional
@property(nonatomic) UITextAutocapitalizationType autocapitalizationType; // default is UITextAutocapitalizationTypeSentences
@property(nonatomic) UITextAutocorrectionType autocorrectionType; // default is UITextAutocorrectionTypeDefault
@property(nonatomic) UITextSpellCheckingType spellCheckingType NS_AVAILABLE_IOS(5_0); // default is UITextSpellCheckingTypeDefault;
@property(nonatomic) UIKeyboardType keyboardType; // default is UIKeyboardTypeDefault
@property(nonatomic) UIKeyboardAppearance keyboardAppearance; // default is UIKeyboardAppearanceDefault
@property(nonatomic) UIReturnKeyType returnKeyType; // default is UIReturnKeyDefault (See note under UIReturnKeyType enum)
@property(nonatomic) BOOL enablesReturnKeyAutomatically; // default is NO (when YES, will automatically disable return key when text widget has zero-length contents, and will automatically enable when text widget has non-zero-length contents)
@property(nonatomic,getter=isSecureTextEntry) BOOL secureTextEntry; // default is NO
@end
這不是我們常用的UITextField一些屬性嗎,我們可以實現(xiàn)這個協(xié)議來實現(xiàn)一些自定義的東西逾柿。下面我們來實現(xiàn)支付密碼樣式的文本框代碼很簡單就不多說了直接看:
#import <UIKit/UIKit.h>
@interface SBPasswordTextField : UIView <UIKeyInput,UITextInputTraits>
@property (nonatomic, copy, readonly)NSString *text;
@property (nonatomic, strong) UIColor *septaLineColor; // defaut black
@property (nonatomic, assign) CGFloat septaLineWidth; //default 1.0px
@property (nonatomic, strong) UIColor *dotFillColor; //default black
@property (nonatomic, assign) CGFloat dotRadius; //default 5.0
@property (nonatomic, strong) UIColor *textColor; //default black
@property (nonatomic, strong) UIFont *font; //default 14;
@property (nonatomic, assign) NSUInteger passwordLength; //default 6;
#pragma mark- UITextInputTraits
@property(nonatomic) UIKeyboardType keyboardType;
@property(nonatomic) UIReturnKeyType returnKeyType;
@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
m.文件
#import "SBPasswordTextField.h"
@interface SBPasswordTextField ()
@property (nonatomic, strong)NSMutableString * innerText;
@property (nonatomic, strong)NSMutableArray *dotsLayers;
@property (nonatomic, strong)NSMutableArray *subTextLayers;
@property (nonatomic, assign)BOOL didLayoutSubview;
@end
@implementation SBPasswordTextField
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup {
_innerText = [NSMutableString new];
_dotsLayers = [NSMutableArray arrayWithCapacity:6];
_subTextLayers = [NSMutableArray arrayWithCapacity:6];
_dotRadius = 5.f;
_dotFillColor = [UIColor blackColor];
_font = [UIFont systemFontOfSize:14];
_textColor = [UIColor blackColor];
_septaLineColor = [UIColor darkGrayColor];
_septaLineWidth = 1.f;
_keyboardType = UIKeyboardTypeNumberPad;
_returnKeyType = UIReturnKeyDone;
_secureTextEntry = YES;
_passwordLength = 6;
_secureTextEntry = YES;
self.backgroundColor = [UIColor whiteColor];
}
- (void)layoutSubviews {
if (_didLayoutSubview) {
return;
}
[super layoutSubviews];
CGSize size = self.bounds.size;
CGFloat gridWith = size.width*1.0/_passwordLength;
CAShapeLayer *gridLayer = [CAShapeLayer layer];
gridLayer.frame = self.bounds;
gridLayer.strokeColor = _septaLineColor.CGColor;
gridLayer.lineWidth = _septaLineWidth;
UIBezierPath *gridPath = [UIBezierPath bezierPath];
[gridPath moveToPoint:CGPointMake(0, _septaLineWidth/2.0)];
[gridPath addLineToPoint:CGPointMake(size.width, _septaLineWidth/2.0)];
[gridPath moveToPoint:CGPointMake(size.width, size.height-_septaLineWidth/2.0)];
[gridPath addLineToPoint:CGPointMake(0, size.height-_septaLineWidth/2.0)];
[gridPath moveToPoint:CGPointMake(_septaLineWidth/2.0, _septaLineWidth)];
[gridPath addLineToPoint:CGPointMake(_septaLineWidth/2.0, size.height-_septaLineWidth)];
for (int i = 1; i<= _passwordLength; ++i) {
[gridPath moveToPoint:CGPointMake(gridWith*i-_septaLineWidth/2.0, _septaLineWidth/2)];
[gridPath addLineToPoint:CGPointMake(gridWith*i-_septaLineWidth/2.0, size.height-_septaLineWidth/2)];
}
gridLayer.path = gridPath.CGPath;
[self.layer addSublayer:gridLayer];
_didLayoutSubview = YES;
}
/**
* 生成小黑點
*
* @param index 第幾個
*
* @return 當(dāng)前小黑點
*/
- (CAShapeLayer *)makeBlackDotLayerAtIndex:(NSUInteger)index {
CAShapeLayer *layer = [CAShapeLayer layer];
layer.fillColor = _dotFillColor.CGColor;
CGSize size = self.bounds.size;
CGFloat gridWith = size.width*1.0/_passwordLength;
layer.path = [self circlePathWithCenter:CGPointMake(gridWith*0+gridWith/2.0, size.height/2.0)].CGPath;
return layer;
}
/**
* 生成text 文本 注意 這種方式不適成大量文本
*
* @param index 第幾個
*
* @return 當(dāng)前文本
*/
- (CATextLayer *)makeTextLayerAtIndex:(NSUInteger)index {
CATextLayer *textLayer = [CATextLayer layer];
textLayer.alignmentMode = kCAAlignmentCenter;
textLayer.wrapped = YES;
textLayer.string = [_innerText substringWithRange:NSMakeRange(index, 1)];
textLayer.contentsScale = [UIScreen mainScreen].scale;
CFStringRef fontName = (__bridge CFStringRef)_font.fontName;
CGFontRef fontRef = CGFontCreateWithFontName(fontName);
textLayer.font = fontRef;
textLayer.fontSize = _font.pointSize;
textLayer.foregroundColor = _textColor.CGColor;
CGFontRelease(fontRef);
return textLayer;
}
/**
* 計算實心小圓點
*
* @param center 圓心
*
* @return 圓的路徑
*/
- (UIBezierPath *)circlePathWithCenter:(CGPoint)center{
return [UIBezierPath bezierPathWithArcCenter:center radius:_dotRadius startAngle:0 endAngle:2*M_PI clockwise:YES];
}
- (NSString *)text {
return [_innerText copy];
}
#pragma mark -
#pragma mark Respond to touch and become first responder.
- (BOOL)canBecomeFirstResponder {
return YES;
}
#pragma mark -
#pragma mark UIKeyInput Protocol Methods
- (BOOL)hasText {
return (self.innerText.length >0);
}
- (void)insertText:(NSString *)theText {
if (_innerText.length == _passwordLength) {
return;
}
[self.innerText appendString:theText];
[self addBlackDotOrTextAtIndex:_innerText.length-1];
}
/**
* 添加小圓點或文本到相應(yīng)的框內(nèi)
*
* @param index 位置
*/
- (void)addBlackDotOrTextAtIndex:(NSUInteger)index {
if (_secureTextEntry) {
CAShapeLayer *layer = [self makeBlackDotLayerAtIndex:index];
CGSize size = self.bounds.size;
CGFloat gridWith = size.width*1.0/_passwordLength;
layer.frame = CGRectMake(gridWith*index, 0, gridWith, size.height);
[self.layer addSublayer:layer];
[_dotsLayers addObject:layer];
} else {
CATextLayer *layer = [self makeTextLayerAtIndex:index];
CGSize size = self.bounds.size;
CGFloat gridWith = size.width*1.0/_passwordLength;
layer.frame = CGRectMake(gridWith*index, (size.height-_font.pointSize-2)/2.0, gridWith,_font.pointSize+2);
[self.layer addSublayer:layer];
[_subTextLayers addObject:layer];
}
}
/**
* 刪除文本
*/
- (void)deleteText {
if (_secureTextEntry) {
CAShapeLayer *layer = [_dotsLayers lastObject];
[layer removeFromSuperlayer];
[_dotsLayers removeLastObject];
}else{
CATextLayer *layer = [_subTextLayers lastObject];
[layer removeFromSuperlayer];
[_subTextLayers removeLastObject];
}
}
代碼很簡單自己又定義了一些屬性可以方便的實現(xiàn)自定義的一些效果:比如邊框顏色 缀棍,邊框粗細(xì),黑色圓點的大小机错,顏色爬范,明文狀態(tài)的文字大小,顏色等弱匪。也支持xib 拖個View 只需改成相關(guān)的類就可以了青瀑。項目還很粗糙(上傳到了GitHub了地址:
https://github.com/lsb332/SBPasswordTextField)
只是提供一種思路而已,附兩張實現(xiàn)圖: