學(xué)習(xí)計(jì)劃 (1)- 自定義文本框

我這做的大概內(nèi)容是:
自定義控件
UITableView在項(xiàng)目中遇到的實(shí)際問(wèn)題探討
iOS系統(tǒng)自帶的動(dòng)畫(huà)
自定義動(dòng)畫(huà)
WKWebView中在實(shí)際項(xiàng)目中遇到的問(wèn)題探討
還有就是一些可能看到哪個(gè)軟件上面的效果想自己實(shí)現(xiàn)以下的吧。
當(dāng)然,如果大家有什么想要實(shí)現(xiàn)的,也可以留言,我可以考慮實(shí)現(xiàn)一下的,也免得我去想100個(gè)項(xiàng)目了,畢竟比較懶。

第一天嘛,就簡(jiǎn)單點(diǎn),來(lái)個(gè)自定義的文本框,也是我項(xiàng)目中實(shí)際出現(xiàn)的:


手機(jī)號(hào)輸入框.png
密碼輸入框.png
提現(xiàn)輸入框.png

如大家所看到那樣,就是三種輸入框,這個(gè)在很多軟件上都有,實(shí)現(xiàn)起來(lái)也比較簡(jiǎn)單。

第一種:透明帶圖的框
就是邊框色沒(méi)有了,寬度也沒(méi)有了。leftView設(shè)置成了圖片,文字往左邊移動(dòng)了一點(diǎn)點(diǎn)
第二種: 同理的邊框透明,但leftView設(shè)置了文字
第三種區(qū)別就是多了rightView

仔細(xì)分析可以看出來(lái),它們其實(shí)都是一種文本輸入框,只是一些樣式的變化。所以可以做成一種類(lèi)起對(duì)待。
只不過(guò)我們?cè)趧?chuàng)建的時(shí)候區(qū)分一下就行了。
區(qū)分某種類(lèi)別,一般是用枚舉了,因?yàn)椴町惥褪鞘欠袷蔷哂邢聞澗€的。所以我們大致分為兩種:

typedef NS_ENUM(NSInteger,GWTextFieldStyle){
    GWTextFieldStyleWithNormal,    //正常
    GWTextFieldStyleWithUnline,    //下滑線
};

然后由于屬性的多樣化,我們的需求可能根據(jù)產(chǎn)品汪的變化而變化,但是我們又不想隨便的去更改一個(gè)已經(jīng)寫(xiě)好的類(lèi),所以我是決定使用一個(gè)model來(lái)作為參數(shù),這樣的話,以后修改model就可以了,不會(huì)去干擾樣式代碼造成什么問(wèn)題。

#import <Foundation/Foundation.h>
/**
 自定義輸入框控件數(shù)據(jù)源
 */
@interface GWTextFieldModel : NSObject
//標(biāo)題內(nèi)容
@property (nonatomic,readwrite,strong)id titleViewContent;
//右視圖內(nèi)容
@property (nonatomic,readwrite,strong)id rightViewContent;
//文本顏色
@property (nonatomic,readwrite,strong)UIColor *textColor;
//邊框線寬度
@property (nonatomic,readwrite,unsafe_unretained)CGFloat borderWidth;
//邊框線顏色
@property (nonatomic,readwrite,strong)UIColor *borderColor;
//背景顏色
@property (nonatomic,readwrite,strong)UIColor *backgroundColor;
//默認(rèn)提示語(yǔ)
@property (nonatomic,readwrite,copy)NSString *placeholder;
//默認(rèn)提示語(yǔ)顏色
@property (nonatomic,readwrite,strong)UIColor *placeHolderColor;
//鍵盤(pán)類(lèi)型
@property (nonatomic,readwrite,unsafe_unretained)UIKeyboardType keyboardType;
//是否顯示密碼
@property (nonatomic,readwrite,unsafe_unretained)BOOL isPassword;

@end

可以看到我在model當(dāng)中存在了兩個(gè)特殊的參數(shù),貌似與屬性無(wú)關(guān),而且還是id類(lèi)型

titleViewContent
rightViewContent

我是設(shè)想通過(guò)titleViewContent就可以直接分辨出文字或者視圖,使得在調(diào)用的時(shí)候直接填入?yún)?shù)就可以了。
而rightViewContent也是同理,如果添加了rightView的情況下,我們加入即可。也就是說(shuō),我們只需要填入?yún)?shù),其它我們?cè)趦?nèi)部直接進(jìn)行實(shí)現(xiàn)。

創(chuàng)建好model之后,我們就可以創(chuàng)建我們的自定義文本框了:

#import <UIKit/UIKit.h>
@class GWTextFieldModel;

typedef NS_ENUM(NSInteger,GWTextFieldStyle){
    GWTextFieldStyleWithNormal,    //正常
    GWTextFieldStyleWithUnline,    //下滑線
};


/**
 自定義輸入框控件類(lèi)
 */
@interface GWTransTextField : UITextField<UITextFieldDelegate>


/**
 創(chuàng)建一個(gè)默認(rèn)樣式的輸入框·

 @param frame 布局
 @param textFieldModel 文本框?qū)傩栽O(shè)置數(shù)據(jù)源
 @return instance of GWTransTextField
 */
+ (instancetype)createNormalTextFieldWithFrame:(CGRect)frame
                                textFieldModel:(GWTextFieldModel *)textFieldModel;


/**
 創(chuàng)建一個(gè)帶有下劃線的輸入框

 @param frame 布局
 @param textFieldModel 文本框?qū)傩栽O(shè)置數(shù)據(jù)源
 @return instance of GWTransTextField
 */
+(instancetype)createUnlineTextFieldWithFrame:(CGRect) frame
                               textFieldModel:(GWTextFieldModel *)textFieldModel;


這里有幾個(gè)習(xí)慣需要注意的:

1. 在.h文件中,一般不要直接#import一個(gè)類(lèi),使用@class就可以了,這樣就不用一編譯時(shí)就導(dǎo)入文件了。
然后在.m文件中使用#import導(dǎo)入文件,也就是說(shuō)我們只需要在運(yùn)行時(shí)去導(dǎo)入文件。

2. 給類(lèi)添加注釋。有必要的話,最好還要解釋一下這個(gè)類(lèi)的功能。 這樣方便你自己和別人第一時(shí)間知道這個(gè)類(lèi)的作用。
短時(shí)間還好,時(shí)間長(zhǎng)了,對(duì)于類(lèi)沒(méi)那么熟悉的時(shí)候,就會(huì)產(chǎn)生遲鈍,造成多余的熟悉時(shí)間成本。

3.就是寫(xiě)注釋了,這是個(gè)必須的工作。

從上面方法的創(chuàng)建,我們可以看到,我將其分為默認(rèn)類(lèi)型的,就是我們常用的文字開(kāi)頭,不透明文本框,還有一種帶下劃線且透明的輸入框。

那么我們?cè)谑菍?shí)現(xiàn)的時(shí)候,就可以了解到,我們?cè)趯?shí)現(xiàn)默認(rèn)文本框的時(shí)候,自由度比較高,它們的屬性基本都是由外界的model所決定。而具有下劃線的文本框,很多樣式已經(jīng)固定了。所以就形成了如下的結(jié)果:

#pragma mark - 初始化默認(rèn)文本框
- (instancetype)initWithNormalFrame:(CGRect)frame textFieldModel:(GWTextFieldModel *)textFieldModel{
    if(self = [super initWithFrame:frame])
    {
        textFieldModel.placeHolderColor = nil;
        [self createUILayoutWithModel:textFieldModel textFieldStyle:GWTextFieldStyleWithNormal];
    }
    return  self;
}
#pragma mark - 初始化下劃線文本框
- (instancetype)initWithUnlineFrame:(CGRect)frame textFieldModel:(GWTextFieldModel *)textFieldModel{
    if(self = [super initWithFrame:frame])
    {
        textFieldModel.placeHolderColor = [PMBTools colorWithHexString:@"#BEBEBE"];
        textFieldModel.borderWidth = 0;
        textFieldModel.textColor = [UIColor whiteColor];
        textFieldModel.borderColor = [UIColor clearColor];
        textFieldModel.backgroundColor = [UIColor clearColor];
        [self createUILayoutWithModel:textFieldModel textFieldStyle:GWTextFieldStyleWithUnline];
    }
    return  self;
}

可以看到,我們?cè)谠O(shè)定默認(rèn)文本框方法的時(shí)候,里面并沒(méi)有具體的參數(shù)設(shè)置,而在下劃線的初始化方法中,我們?cè)O(shè)置了很多默認(rèn)的屬性。也就是說(shuō),將必要的東西盡量去封裝。

這里要提的習(xí)慣就是:

使用#pragma mark 命令,通過(guò)該命令,可以形成如下圖的導(dǎo)航效果,可以快速定位你寫(xiě)的方法。
使用#pragma mark - 命令可以形成分組效果
導(dǎo)航.png

下面我們就進(jìn)入到重點(diǎn)了,如何進(jìn)行識(shí)別titleViewContent的類(lèi)型?

if([textFieldModel.titleViewContent isKindOfClass:[NSString class]]){
      //實(shí)現(xiàn)將文本框作為leftView
}else if([textFieldModel.titleViewContent isKindOfClass:[UIImage class]]){
      //實(shí)現(xiàn)將圖片設(shè)為leftView
}else if([textFieldModel.titleViewContent isKindOfClass:[UIView class]]){
      //實(shí)現(xiàn)將普通視圖設(shè)為leftView
}

if([textFieldModel.rightViewContent isKindOfClass:[UIView class]]){
      //實(shí)現(xiàn)將普通視圖設(shè)為rightView
}

通過(guò)isKindOfClass方法,我們判斷出我們的titleViewContent是什么類(lèi)型的,我們就可以根據(jù)不同的類(lèi)型進(jìn)行處理。
當(dāng)然咯,你會(huì)發(fā)現(xiàn)這樣做之后,單純的去設(shè)置leftView什么的還是顯示不出來(lái),那是因?yàn)?,leftViewMode的問(wèn)題

typedef NS_ENUM(NSInteger, UITextFieldViewMode) {
    UITextFieldViewModeNever,
    UITextFieldViewModeWhileEditing,
    UITextFieldViewModeUnlessEditing,
    UITextFieldViewModeAlways
};

系統(tǒng)默認(rèn)的是UITextFieldViewModeNever,它并不會(huì)顯示,所以我們要將該值設(shè)置成UITextFieldViewModeAlways,讓它一直顯示。

self.leftView = _titleView;
self.leftViewMode = UITextFieldViewModeAlways;

當(dāng)我們做完基本的屬性設(shè)置之后,就可以調(diào)用,并顯示了。

@property (nonatomic,readwrite,strong)GWTransTextField *txtUserName;

- (GWTransTextField *)txtUserName{
    if(!_txtUserName){
        CGFloat margin = 20;
        CGFloat height = 50;
        GWTextFieldModel *textFieldModel = [GWTextFieldModel new];
        textFieldModel.placeholder = @"請(qǐng)輸入手機(jī)密碼";
        textFieldModel.titleViewContent = [UIImage imageNamed:@"Phone"];
        _txtUserName = [GWTransTextField createUnlineTextFieldWithFrame:
                       (CGRect){margin,200,kSCREENWIDTH-margin*2,height} textFieldModel:textFieldModel];
    }return _txtUserName;
}

簡(jiǎn)單的創(chuàng)建,添加之后,我們會(huì)發(fā)現(xiàn),效果不太好


開(kāi)始的效果.png

這圖片和字怎么都擠一塊去了,完全不符合我們比產(chǎn)品汪還要好的審美啊,所以我們需要調(diào)整樣式
調(diào)整樣式需要重寫(xiě)父類(lèi)方法

- (CGRect)textRectForBounds:(CGRect)bounds

這里的bounds參數(shù),就是當(dāng)前文本框的bounds,所以直接調(diào)整就可以了。

    bounds.origin.x = marginLeft(_titleView) + 15;
    //如果有右視圖的話,文本框輸入的范圍要縮小到右視圖的前面
    if(_rightView){
        bounds.size.width = bounds.size.width-bounds.origin.x-_rightView.bounds.size.width-15;
    }

如果還需要調(diào)整圖標(biāo)大小,方位什么的需要重寫(xiě)該方法:

- (CGRect)leftViewRectForBounds:(CGRect)bounds{
    bounds.origin.x = 10;
    bounds.origin.y = bounds.size.height/2-imageSize.height/2;
    bounds.size.width = imageSize.width;
    bounds.size.height = imageSize.height;
}
- (CGRect)rightViewRectForBounds:(CGRect)bounds;

如果你在實(shí)現(xiàn)的過(guò)程中遇到 輸入的時(shí)候文本框出現(xiàn)樣式問(wèn)題就實(shí)現(xiàn)重寫(xiě)如下方法,保持與textRectForBounds方法樣式一致了,反正我是遇到過(guò)的。

- (CGRect)editingRectForBounds:(CGRect)bounds

最終的樣式


手機(jī)號(hào)輸入框.png

如果你需要添加在尾部的清除按鈕:


清楚按鈕.png
self.clearButtonMode = UITextFieldViewModeWhileEditing;
同理,mode也是分了各種情況,包括,, 
typedef NS_ENUM(NSInteger, UITextFieldViewMode) {
    UITextFieldViewModeNever, //不顯示
    UITextFieldViewModeWhileEditing,//有內(nèi)容,輸入的時(shí)候顯示
    UITextFieldViewModeUnlessEditing,//有內(nèi)容,不輸入的時(shí)候顯示
    UITextFieldViewModeAlways//有內(nèi)容,一直顯示
};

調(diào)用的話如下所示:

- (GWTransTextField *)txtUserName{
    if(!_txtUserName){
        NSInteger buttonMargin = 20;
        CGFloat buttonHeight = 50;
        GWTextFieldModel *textFieldModel = [GWTextFieldModel new];
        textFieldModel.placeholder = @"請(qǐng)輸入手機(jī)密碼";
        textFieldModel.titleViewContent = [UIImage imageNamed:@"Phone"];
        _txtUserName = [GWTransTextField createUnlineTextFieldWithFrame:(CGRect){buttonMargin,200,kSCREENWIDTH-buttonMargin*2,buttonHeight} textFieldModel:textFieldModel];
    }return _txtUserName;
}

然后直接添加到view中即可。

最后三種實(shí)現(xiàn)的效果如下:


最終效果.png

最后貼上代碼地址:
https://github.com/yanggenwei/GWTextField

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評(píng)論 19 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,365評(píng)論 25 708
  • 有時(shí)候問(wèn)自己, 我們過(guò)的如此不易, 為什么還如勇士般的拼搏著呢? 或許是我想看看, 在我瞑目之前還會(huì)發(fā)生什么我想不...
    想想看看吧閱讀 476評(píng)論 0 4
  • 煙雨蒙蒙的午后 某個(gè)車(chē)站的入口 我們像兩條魚(yú) 朝著不同的方向游走 相聚如此匆匆 如蒙蒙細(xì)雨劃過(guò)天空 我們一起走過(guò)的...
    楊畫(huà)畫(huà)閱讀 436評(píng)論 2 3
  • 關(guān)于職業(yè) 這世上大約有很多人沒(méi)有體會(huì)過(guò),做一份熱愛(ài),擅長(zhǎng),出產(chǎn)價(jià)值的工作,然后從中自我實(shí)現(xiàn)是怎樣的感覺(jué)——所有的快...
    只認(rèn)識(shí)瘦的自己閱讀 233評(píng)論 0 0

友情鏈接更多精彩內(nèi)容