最近同樣是新App,設計稿里出現一種圓形進度條的設計,如下:
想了想,圓形進度條實現起來不難,但是其中顯示百分比的文本確需要自適應,雖然可以使用時自己設定文本字體的大小,但是這樣顯得很麻煩,也很low。
查了一圈,目前實現的自適應UILabel,都是根據font大小動態調整frame的size,並不能滿足我們的需求。
那么問題來了
如何實現一種能夠根據frame大小自適應調整文本font size的圓形進度條呢?
我的實現思路很簡單,首先計算出能夠給予UILabel的frame最大尺寸,然后根據高度優先,寬度次之的原則,計算出最合適的字體大小,這樣可以完美的適配各種尺寸。
效果如下:
實現代碼:
CircleProgressBar繼承於UIView,具有四個屬性,分別如下:
// // CircleProgressBar.h // demo // // Created by ZhangChangwei on 15/4/1. // Copyright (c) 2015年 Changwei. All rights reserved. // #import <UIKit/UIKit.h> @interface CircleProgressBar : UIView
//進度條百分比值 @property (nonatomic) float percentValue;
//進度條寬度 @property (nonatomic) float lineWidth;
//文本顏色 @property (nonatomic ) UIColor *textColor;
//進度條顏色 @property (nonatomic ) UIColor *barColor; @end
實現方式主要采用CoreGraphics繪制圖形,其中文字繪制采用自適應計算大小的方式實現,實現了根據控件frame大小動態改變字體的行為,非常靈活。
// // CircleProgressBar.m // demo // // Created by ZhangChangwei on 15/4/1. // Copyright (c) 2015年 Changwei. All rights reserved. // #import "CircleProgressBar.h" @implementation CircleProgressBar /** * init and set up property * * @param frame <#frame description#> * * @return <#return value description#> */ -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { } return self; } /** * redraw * * @param rect frame */ - (void)drawRect:(CGRect)rect { if(_lineWidth==0.0f){ _percentValue=0; NSLog(@"%@",@"請輸入顏色,數值等參數"); } //開始繪制圖形 CGContextRef ctx=UIGraphicsGetCurrentContext(); CGContextSetLineWidth(ctx, _lineWidth); CGContextBeginPath(ctx); CGContextSetStrokeColorWithColor(ctx, _barColor==nil?[UIColor orangeColor].CGColor:_barColor.CGColor); CGContextAddArc(ctx, self.frame.size.width/2, self.frame.size.width/2, self.frame.size.width/2-_lineWidth, M_PI*1.5, M_PI*(1.5-2*_percentValue), 1); CGContextStrokePath(ctx); //繪制計算最佳文本大小 CGSize maxSize=CGSizeMake(rect.size.width*0.75, rect.size.height/3); int currentFontSize=17; NSString *str=[NSString stringWithFormat:@"%.1f%%",_percentValue*100]; CGSize requiredSize = [str boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize]} context:nil].size; if(requiredSize.height<=maxSize.height) { while (requiredSize.height<=maxSize.height&&requiredSize.width<maxSize.width) { currentFontSize++; requiredSize=[str boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize]} context:nil].size; } }else { while (requiredSize.height>maxSize.height||requiredSize.width>maxSize.width) { currentFontSize--; requiredSize=[str boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize]} context:nil].size; } requiredSize=[str boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize]} context:nil].size; } //繪制自適應文本 [str drawAtPoint:CGPointMake(rect.size.width/2-requiredSize.width/2, rect.size.height/2-requiredSize.height/2) withAttributes:@{ NSFontAttributeName:[UIFont systemFontOfSize:currentFontSize], NSForegroundColorAttributeName:_textColor==nil?[UIColor blackColor]:_textColor }]; } @end
使用方法:
CircleProgressBar使用起來非常簡單,只需要提供相應參數即可,如下:
- (void)viewDidLoad { [super viewDidLoad]; CircleProgressBar *bar1=[[CircleProgressBar alloc] initWithFrame:CGRectMake(SCREEN_WIDTH/2-10, SCREEN_HEIGHT*0.2, 20, 20)]; bar1.barColor=[UIColor redColor]; bar1.lineWidth=1.0f; bar1.percentValue=0.85; bar1.backgroundColor=[UIColor clearColor]; [self.view addSubview:bar1]; CircleProgressBar *bar2=[[CircleProgressBar alloc] initWithFrame:CGRectMake(SCREEN_WIDTH/2-25, SCREEN_HEIGHT*0.3, 50, 50)]; bar2.barColor=[UIColor orangeColor]; bar2.lineWidth=3; bar2.percentValue=0.45; bar2.backgroundColor=[UIColor clearColor]; [self.view addSubview:bar2]; CircleProgressBar *bar3=[[CircleProgressBar alloc] initWithFrame:CGRectMake(SCREEN_WIDTH/2-50, SCREEN_HEIGHT*0.5, 100, 100)]; bar3.barColor=[UIColor greenColor]; bar3.lineWidth=5; bar3.textColor=[UIColor blueColor]; bar3.percentValue=0.75; bar3.backgroundColor=[UIColor clearColor]; [self.view addSubview:bar3]; CircleProgressBar *bar4=[[CircleProgressBar alloc] initWithFrame:CGRectMake(SCREEN_WIDTH/2-100, SCREEN_HEIGHT*0.7, 200, 200)]; bar4.barColor=[UIColor blueColor]; bar4.textColor=[UIColor purpleColor]; bar4.lineWidth=10; bar4.percentValue=0.55; bar4.backgroundColor=[UIColor clearColor]; [self.view addSubview:bar4]; }
完成了圓形進度條的實現后,想了想,其實可以加入動畫,使得進度條動態展現,下次有時間再實現😁