我這做的大概內(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)的:



如大家所看到那樣,就是三種輸入框,這個(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 - 命令可以形成分組效果

下面我們就進(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),效果不太好

這圖片和字怎么都擠一塊去了,完全不符合我們比產(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
最終的樣式

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

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)的效果如下:
