后續(xù)文章也同時(shí)在個(gè)人博客 http://kimihe.com/ 更新
引言
在上一篇文章中盯捌,我們提到會(huì)通過編寫一個(gè)progressView來學(xué)習(xí)自定義控件淮韭,在學(xué)習(xí)了layoutSubviews之后,我們對于控件布局有了更多的了解。
在這篇文章中授霸,我們將會(huì)講解如何自己實(shí)現(xiàn)一個(gè)porgressView召娜,并一次來說明如何繼承UIView來編寫自己的控件闸与。
為了簡便地講解恰力,我們的porgressView將會(huì)按照alert的形式來展現(xiàn),請注意以下幾個(gè)說明:
- porgressView將會(huì)置頂于屏幕層級(jí)陡蝇。
- porgressView的frame大小將不需要用戶改變痊臭,是一個(gè)固定的大小。
- 我們不使用layoutSubviews來控制布局登夫,而是更加關(guān)注自定義控件如何實(shí)現(xiàn)功能广匙。
- 關(guān)于如何在實(shí)際工程中使用layoutSubviews,可以參考我的另一個(gè)demo:BezierCurve_Test恼策。
- 我已經(jīng)將博客中所用到的demo都集成到了KMiOSLib鸦致,歡迎大家下載!
Demo地址
Demo結(jié)構(gòu)
Demo關(guān)鍵部分由KMUIKitMacro.h
,KMProgressView
類分唾,以及ViewController
類構(gòu)成抗碰。
-
KMUIKitMacro.h
是一些預(yù)定義的宏,用于簡化代碼绽乔。 -
KMProgressView
類就是我們實(shí)現(xiàn)的自定義控件改含,后文會(huì)著重講解它。 -
ViewController
類結(jié)合storyboard使用我們的自定義控件迄汛。 - KMProgressView的使用在頭文件
KMProgressView.h
有詳細(xì)的注釋,大家可以快速掌握使用方法骤视。 - storyboard中有一段說明性的文字鞍爱,其下是兩個(gè)button,ProgressCompleted模擬網(wǎng)速良好专酗,進(jìn)度條成功執(zhí)行完畢的情況睹逃。ProgressFailed則模擬中途失敗停止的情況。
原理講解
我們接下來著重講解KMProgressView
類的實(shí)現(xiàn)原理祷肯。
正如上文說明的沉填,我們的KMProgressView是不需要用戶控制其frame大小的,作為彈窗它的布局應(yīng)該固定佑笋,只需要根據(jù)不同機(jī)型的屏幕尺寸做略微的調(diào)整翼闹。關(guān)于屏幕尺寸的獲取,可以見KMUIKitMacro.h
中的宏蒋纬。
//獲取屏幕 寬度猎荠、高度
#define kSCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width) //!< UIScreen寬度
#define kSCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height) //!< UIScreen高度
初始化方法
-
init
方法
//此處沒有重寫initWithFrame方法,因?yàn)閜rogressView類似于alert蜀备,其大小不需要人為再去設(shè)定
- (instancetype)init
{
self = [super initWithFrame:CGRectMake(0, 0, kboxImageView_width, kboxImageView_height)];
if (self) {
[self drawProgressViewWithFrame:CGRectMake(0, 0, kboxImageView_width, kboxImageView_height)];
}
return self;
}
-
initWithColor:
方法
- (instancetype)initWithCoverColor:(UIColor *)color
{
self = [super initWithFrame:CGRectMake(0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT)];
if (self) {
[self drawCoverView];
[self drawProgressViewWithFrame:CGRectMake(0, 0, kboxImageView_width, kboxImageView_height)];
}
return self;
}
我們在初始化方法中关摇,并不需要重寫initWithFrame:
方法,在這里我提供了兩種初始化方法:init
和initWithCoverColor:
碾阁。大家可以注意到输虱,Apple原生的alert是帶有深色透明背景的,可以突出alert的顯示脂凶。我們這里也會(huì)采用宪睹,對于底色我將其稱作遮罩(cover)。
知道了這一點(diǎn)艰猬,上述兩種初始化方法等區(qū)別就很簡單了横堡,前者不帶有遮罩,出現(xiàn)progressView后冠桃,用戶仍舊可以點(diǎn)擊到位于其下方的其他控件命贴。而后者則會(huì)有一個(gè)遮罩,阻止用戶的其他操作,并使progressView顯得更加醒目胸蛛。此外我們遮罩的顏色是可以在初始化時(shí)指定的污茵。
遮罩
遮罩我們在drawCoverView
方法中實(shí)現(xiàn):
- (void)drawCoverView
{
//底色遮罩
_boxCoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, kSCREEN_WIDTH, kSCREEN_HEIGHT)];
_boxCoverView.backgroundColor = [UIColor blackColor];
_boxCoverView.alpha = 0.8;
[self insertSubview:_boxCoverView atIndex:0];
}
我們根據(jù)屏幕尺寸設(shè)置遮罩的frame,然后把它作為progressView的最底層葬项。
圖層繪制
具體的繪制我們在``方法中實(shí)現(xiàn):
- (void)drawProgressViewWithFrame:(CGRect)frame
{
self.backgroundColor = [UIColor clearColor];
//背景圖
_boxImageView = [[UIImageView alloc] initWithFrame:frame];
_boxImageView.backgroundColor = colorFromRGBA(0xFFFFFF, 1.0);
_boxImageView.image = [UIImage imageNamed:@"YourPicture"];
_boxImageView.center = self.center;
_boxImageView.layer.cornerRadius = 5.0;
_boxImageView.layer.masksToBounds = YES;
[self addSubview:_boxImageView];
//標(biāo)題
_boxTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(kboxTitleLabel_x, kboxTitleLabel_y, kboxTitleLabel_width, kboxTitleLabel_height)];
_boxTitleLabel.textColor = colorFromRGBA(0x333333, 1.0);
_boxTitleLabel.font = [UIFont systemFontOfSize:18.0];
_boxTitleLabel.text = @"Your Title";
_boxTitleLabel.textAlignment = NSTextAlignmentCenter;
_boxTitleLabel.adjustsFontSizeToFitWidth = YES;
[_boxImageView addSubview:_boxTitleLabel];
//進(jìn)度數(shù)值
_boxNumberlabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, kboxNumberlabel_width, kboxNumberlabel_height)];
_boxNumberlabel.textColor = [UIColor whiteColor];
_boxNumberlabel.backgroundColor = colorFromRGBA(0xFC5832, 1.0);
_boxNumberlabel.text = @"0%";
_boxNumberlabel.textAlignment = NSTextAlignmentCenter;
_boxNumberlabel.layer.cornerRadius = 4.0;
_boxNumberlabel.layer.masksToBounds = YES;
_boxNumberlabel.adjustsFontSizeToFitWidth = YES;
_boxNumberlabel.layer.anchorPoint = CGPointMake(0.5, 0.0);
_boxNumberlabel.layer.position = CGPointMake(kboxNumberlabel_x, kboxNumberlabel_y);
[_boxImageView addSubview:_boxNumberlabel];
//進(jìn)度條
_boxProgressView = [[UIProgressView alloc] initWithFrame:CGRectMake(kboxProgressView_x, kboxProgressView_y, kboxProgressView_width, kboxProgressView_height)];
_boxProgressView.progressViewStyle = UIProgressViewStyleDefault;
_boxProgressView.trackTintColor = colorFromRGBA(0xCFCFCF, 1.0);
_boxProgressView.progressTintColor = colorFromRGBA(0xFC5832, 1.0);
[_boxImageView addSubview:_boxProgressView];
}
分別是UIImage泞当,UILabel,UIProgressView的添加民珍,其中對于UIImage背景我在這里進(jìn)行了留白襟士,大家可以替換成自己喜愛的圖片。此外我們使用了RGBA的宏嚷量,同樣也可以在KMUIKitMacro.h
中找到陋桂。
//16進(jìn)制表示RGBA
#define colorFromRGBA(rgbValue,trans) [UIColor \
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
blue:((float)(rgbValue & 0xFF))/255.0 alpha:trans]
你可能會(huì)注意到_boxNumberlabel中使用了一些layer相關(guān)的方法,關(guān)于layer蝶溶,之后我也會(huì)結(jié)合BezierCurve_Test另開一篇文章詳細(xì)講解嗜历,這方面的知識(shí)還是比較繁瑣的。
控件屬性的設(shè)置
我們在KMProgressView.h
中提供了幾個(gè)設(shè)置其屬性的方法抖所。
-
- (void)setState:(KMProgressViewState)state withProgress:(float)progress
在該方法中我們根據(jù)狀態(tài)state和進(jìn)度progress來設(shè)置控件的樣式梨州,其中state我們使用了枚舉來包含幾種可能的情況:
typedef NS_ENUM(NSInteger, KMProgressViewState)
{
KMProgressView_Begin,
KMProgressView_Uploading,
KMProgressView_Completed,
KMProgressView_Failed
};
而在progress中,我們根據(jù)它的值來動(dòng)態(tài)顯示進(jìn)度田轧,progress是一個(gè)[0,1]區(qū)間的float值暴匠,0表明剛開始,1表示完成涯鲁。這里我們還用到了layer的一些可動(dòng)畫屬性巷查,我們也會(huì)在今后關(guān)于layer的文章中具體講解。
CGFloat offset = kboxProgressView_width * progress;
_boxNumberlabel.layer.position = CGPointMake(kboxNumberlabel_x + offset, kboxNumberlabel_y);
-
- (void)showAt:(UIView *)view
這是讓控件顯示的方法抹腿,我們通過self.center = view.window.center;
讓控件位于視圖的最頂層岛请。同時(shí)也使用了UIView的一些動(dòng)畫過度方法,它的使用很簡單警绩。 -
- (void)remove
這是讓控件消失崇败,我們通過延遲執(zhí)行來取得更好的動(dòng)畫效果。
如何使用該控件
參考ViewController.m
中的示例肩祥,結(jié)合模擬器運(yùn)行后室,大家可以更好地理解該控件的使用場景。
總結(jié)
本文通過實(shí)際編寫一個(gè)progressView來向大家演示如何自定義一個(gè)控件混狠,涉及到了各種不同的小知識(shí)點(diǎn)岸霹,希望對大家有所幫助。更多繪圖方面的知識(shí)将饺,請繼續(xù)關(guān)注后續(xù)的文章贡避,感謝閱讀痛黎!