如何實(shí)現(xiàn)一個(gè)自定義progressView

后續(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地址

KMProgressViewDemo

Demo結(jié)構(gòu)

Demo關(guān)鍵部分由KMUIKitMacro.hKMProgressView類分唾,以及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:方法,在這里我提供了兩種初始化方法:initinitWithCoverColor:碾阁。大家可以注意到输虱,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)行后室,大家可以更好地理解該控件的使用場景。

運(yùn)行示意圖

總結(jié)

本文通過實(shí)際編寫一個(gè)progressView來向大家演示如何自定義一個(gè)控件混狠,涉及到了各種不同的小知識(shí)點(diǎn)岸霹,希望對大家有所幫助。更多繪圖方面的知識(shí)将饺,請繼續(xù)關(guān)注后續(xù)的文章贡避,感謝閱讀痛黎!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市刮吧,隨后出現(xiàn)的幾起案子湖饱,更是在濱河造成了極大的恐慌,老刑警劉巖杀捻,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件井厌,死亡現(xiàn)場離奇詭異,居然都是意外死亡致讥,警方通過查閱死者的電腦和手機(jī)仅仆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垢袱,“玉大人蝇恶,你說我怎么就攤上這事』掏” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵潘懊,是天一觀的道長姚糊。 經(jīng)常有香客問我,道長授舟,這世上最難降的妖魔是什么救恨? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮释树,結(jié)果婚禮上肠槽,老公的妹妹穿的比我還像新娘。我一直安慰自己奢啥,他們只是感情好秸仙,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著桩盲,像睡著了一般寂纪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赌结,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天捞蛋,我揣著相機(jī)與錄音,去河邊找鬼柬姚。 笑死拟杉,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的量承。 我是一名探鬼主播搬设,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼穴店,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了焕梅?” 一聲冷哼從身側(cè)響起迹鹅,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贞言,沒想到半個(gè)月后斜棚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡该窗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年弟蚀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片酗失。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡义钉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出规肴,到底是詐尸還是另有隱情捶闸,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布拖刃,位于F島的核電站删壮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏兑牡。R本人自食惡果不足惜央碟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望均函。 院中可真熱鬧亿虽,春花似錦、人聲如沸苞也。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽如迟。三九已至坯认,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氓涣,已是汗流浹背牛哺。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留劳吠,地道東北人引润。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像痒玩,于是被迫代替她去往敵國和親淳附。 傳聞我的和親對象是個(gè)殘疾皇子议慰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評(píng)論 25 707
  • 這本“活著”是讀完黃齡慧老師推薦的關(guān)于“教養(yǎng)”的一本書之后才開始讀的。在這里奴曙,我要先說說這本關(guān)于“教養(yǎng)”的書别凹,我把...
    靜待一朵花開閱讀 401評(píng)論 0 0
  • 【姓名】寧靜海 【姓名】寧靜海 【派別】文魁派 【導(dǎo)師】袁文魁 王玉印 【分舵】聞雞起舞 【舵主】劉麗瓊 【導(dǎo)圖說...
    大寧__寧靜海閱讀 248評(píng)論 2 0
  • 線代~炉菲!頭暈,沒事坤溃,這才看多大會(huì)啊拍霜,倆小時(shí)弄懂人家學(xué)了那么久的東西,怎會(huì)那么容易呢薪介,淡定~~加油
    星塵下的貓咪閱讀 302評(píng)論 0 0
  • 今天是你的生日汁政,老婆你辛苦啦道偷! 十八年前,我們相識(shí)记劈,彼時(shí)的我试疙,還是一個(gè)苦澀青年,自從認(rèn)識(shí)了你抠蚣,我開始變得多愁善感,...
    亦農(nóng)閱讀 405評(píng)論 2 1