PaintCode 教程2:自定义进度条

PaintCode 是一个可以让你像Photoshop同样去设计你的用户界面的软件 – 可是它并非仅仅保存一张图片看成资源让你来使用,它可以为你生成 CoreGraphic 源码直接使用到View的绘制中.
在这个系列的第一部分教程中, 咱们已经告诉你们如何去用PaintCode去创造能够随时改变大小,随时改变颜色的自定义按钮.
此次的教程将会教你们如何使用PaintCode去创造设计一个属于本身的进度条,而且将它集成到代码里.
对于看了第一部分教程读者的来讲这篇教程会相对更容易一些。固然,若是没有看过,并没关系,由于这边教程仍然可以详细的带你们一步一步熟悉PaintCode。第一步必定是安装PaintCode,而后下载这个我已经为你们准备好了的初始项目.
话很少说,如今就打开PaintCode开始学习如何建立新的UI控件吧! spring

踏出第一步

在PaintCode中建立一个新的文件, 点击 FileRename…,将它命名为 DynamicProgressIndicator, 而后肯定.
在这个教程中,咱们作得控件并非retina显示的。 任什么时候候若是你须要生成一个retina显示的控件, 在PaintCode窗口的右下角,先点击Retina 按钮, 而后点击 Canvas 按钮就能够了。
若是你打开实时的代码输出panel, 这些按钮将会在窗口最下面这个panel的顶端, 以下图所示:
PaintCode canvas
接下来,为了让canvas更加适合咱们的进度条,咱们将canvas稍微的调小一点, 而后把它的背景色换成一个暗一点的颜色,这样可让看你空间看起来更温馨.
具体步骤是: 点击 Canvas 按钮, 把 canvas 从 320 pixels调整到 70 pixels.而后把Underlay color 调整成以下图同样的灰色. 若是你想要设置成特定的颜色值, 使用 R=45, G=45, B=45, A=255.
Canvas color change
在canvas 一切就绪以后, 咱们能够开始着手为进度条建立基本的 shapes, gradients, 和 colors.
在工具栏选择Round Rect 工具,而后画一个圆角的长方形在canvas上作为咱们控件的外边框. 完成以后选中画好的外边框, 设置这个 shape’s 的属性为以下: canvas

  • X : 2
  • Y : 1
  • Width : 316
  • Height : 34
  • Radius : 4

你的 shape 属性栏应该和下图同样:
Border rounded rectangle
保持外边框继续选中着, 在左边栏里找到 Stroke 设置, 而后把它设置为 No Stroke. 一样的, 找到并点击 Fill 设置, 选择 Add New Gradient…, 而后点击渐变编辑框左下角的那个颜色选取点. 点击右下角的颜色选取按钮,把 RGB 值设置为 to 82 82 82.而后在点击渐变编辑框右下角那个颜色选取点,而且把他的 RGB 值设置为 106 106 106. 最后将这个 gradient 命名为 Outer Rect Gradient.
Renaming the gradienet xcode

注意: 若是之后须要修改PaintCode里的 gradients, colors, 或者 shadows, 你们能够再左边栏下面的 panel 里点击对应的名字的 tab 去修改已命名的属性. 双击须要修改的属性的名字,而后在弹出的dialog里作修改就行了. app

如今咱们先关掉dialog, 在外边框的属性栏里找到 Outer Shadow section. 而后添加一个RGB 值是 51 51 51 的 Outer Shadow. 而后把它命名为 DarkShadow, 以下图所示:
PaintCode outer shadow
接着, 咱们继续加一个浅色的RGB 值为 171 171 171的 Inner Shadow. 命名 LightShadow,以下图所示:
PaintCode inner shadow
最后咱们把这个Rounded Rectangle 的名字改成 Border.每当完成编辑一个元素马上给他一个描述性的名字永远都是一个好的习惯,由于这可让你更好的在你本身的应用里找到他们.
Renaming the Rectangle
到此为止,进度条的基本外边已经完成, 咱们接下来要开始作的是进度槽. ide

制做进度槽和背景

再找到 Round Rect 工具,而后另外拖一个矩形在你的canvas上。 把它属性设置为以下: 工具

  • X : 12
  • Y : 10
  • Width : 292
  • Height : 14
  • Radius : 7

Track rounded rectangle
而后给这个shape的Fill 设置一个新的gradient,左边的颜色选取点的RGB设置为 48 48 48,右边的设置为 63 63 63, 以下图所示:
PaintCode rectangle gradient
设置 Outer Shadow 为 LightShadowInner Shadow 为 DarkShadow, 而后把这个shape命名为ProgressTrack.
教程到这里, 你的空间应该看起来像下图同样了:
Indicator progress
如今咱们来加最后一个可见的元素.
选择Round Rect工具,再拖一个矩形而且把它的属性设置为以下: oop

  • X : 14
  • Y : 12
  • Width : 288
  • Height : 10
  • Radius : 5

最后的这个shape将会在 ProgressTrack 左边缘靠右2像素的位置而且中心垂直对称. 学习

注意:你会发现若是不是去直接修改数值的话,本身手动去修改这个shape的大小和位置会很难,由于进度槽和它的背景太类似了.
固然, 除了直接修改数值,你能够经过下面2种方法达到一样的效果: 1) 选中进度槽背景,复制粘贴,而后把它稍微的修改小一点, 或者 2) 若是你有一个trackpad,用手势把当前的shape放大,这样任然可使制做更加容易。 测试

为了让进度条看起来更加的显眼一点,咱们把进度条改为绿色的— RGB 0 226 0。 你们也能够根据本身爱好去修改颜色。
最后, 把这个shape的 Shadow 和 Inner Shadow 都改为 No Shadow, 取消 Stroke 而后把它更名为 ProgressTrackActive. 如今你的控件应该和下面的差很少了:
Green indicator track
看起来很棒吧 — 可是若是想要它动起来,咱们须要加一些组件来让它动态的响应事件. 动画

加入 Control Frame

有一点须要你们注意的 – 若是你们想在PaintCode里随时的去调整一个元素的大小,那就应该把它放在一个frame里面,,而且去设置他的属性,这样PaintCode才知道如何去调整它的大小当它的parent frame改变的时候。
下面是咱们须要作的:

  1. Group: 把全部你但愿被同一个parent frame调整大小的元素放在一个group里。
  2. Frame: 建立一个frame,而后把全部的元素都放在里面。 选中 Apply only to entirely enclosed shapes来限定这个frame只能影响到在他里面的元素.
  3. Springs  Struts: 为每一个让元素在frame改变的时候知道它们改如何改变本身的大写,你须要设置它们的springs 和 struts。

在上方工具栏选择 Frame tool。在绿色的进度条周围拖出一个fame,以下图所示:
PaintCode dynamic frame
而后把这个fame命名ActiveProgressFrame 而后把它和ProgressTrackActive方框group在一块儿 (同时选中2个而后点击工具栏里的Group)。而后把这个把这个group命名为 ProgressActiveGroup。
再次选中ActiveProgressFrame 而后勾选Apply only to entirely enclosed shapes。 这样能使这个frame只能影响ProgressTrackActive bar,由于ProgressTrackActive 是这个group里惟一放在在ActiveProgressFrame范围内的元素.
为了让进度条水平居中,进度条须要设置为固定高度以及可变的宽度。
首先,咱们须要选中 ProgressTrackActive 而后点击右边和下边的 springs 将他们设置为不可变的。而后点击中间的2个横条将他们变成spring, 以下图所示:
Progress Track Resizing
为了测试刚才作得改动,你能够尝试向右拖动ActiveProgressFrame 的拖动点 。 绿色的横条应该会随着你的拖动拉伸。 若是你们尝试将frame上下拖动,会发现绿色的方框只会水平的拉伸,竖直放假仅仅会跟着frame的边框移动。
为了能让整个进度条随着frame的改动而调整,咱们须要给整个进度条加一个frame。 首先,把全部元素都放在一个group里面 (包含已经建立了的group),而后点击工具栏里的 Group按钮。最后,命名把这个group为Progress Bar。 新的group应该和下图同样:
Progress bar group
接着,选择 Frame 工具,建立一个frame把整个进度条都包含进去。 而后把这个frame加入Progress Bargroup,最后把它命名 ProgressIndicatorFrame.。任然勾选 Apply only to entirely closed shapes,若是你忘记了为何要这样作,能够在看看教程的前几部。
接下来选中 ProgressActiveGroup。 为了让全部的元素都保持本身的位置,向前几步同样,咱们须要设置这个frame只能水平改变大小。
点击 springs/struts 里的水平横条将它变成一个spring。为了让进度槽的位置相对于上左右边框都不会改变, 因此确保只有下面的竖条是一个spring。 下面的图便是frame的具体设置:
Progress active group sizing
将ProgressTrack 和 Border 修改成一样的设置。
如今让咱们开始试试刚才的修改吧!选中ProgressIndicatorFrame而后随便的拖拽改变他的大小 — 进度条应该只会水平的改变大小,竖直方向保持不变。
选中ProgressTrackActive shape 而后点击 variable width 按钮, 这个按钮就在 Width 属性的右边,2个中括号包住一个小圆点的图标。
Progress track active rect width
记住!!!保存你全部的改动。 接下来咱们要开始把进度条和代码联系起来了。

在项目里加入进度条

在 Xcode中,打开刚才下载的初始项目,或者继续你在第一部分教程建立的项目。打开项目以后,展开group Classes > Views。
如今咱们须要作的就是像教程1同样,建立一个进度条的subclass。此次咱们继承的是 UIProgressView ,这样的话,你们用 PaintCode 建立的进度条就拥有和iOS进度条同样的表现了。
右键点击 Views group而后选择 NewFile…. 接着选择iOSCocoa TouchObjective-C class 模板。 把类命名为 ProgressView,而后设置它继承 UIProgressView。
打开 ProgressView.m文件,删除方法 initWithFrame: 而后去掉 drawRect:方法的注释。 下面的这个文件这时候的样子:

[objc]  view plain copy
  1. #import "ProgressView.h"  
  2. @implementation ProgressView  
  3. - (void)drawRect:(CGRect)rect  
  4. {  
  5.     // Drawing code  
  6. }  
  7. @end   

如今咱们能够开始粘贴PaintCode给你的代码了。
回到 PaintCode 而后肯定代码窗口在下面打开着; 若是没有,在菜单里选择 View > Code 。 设置平台为 iOS > Objective-C,系统版本是 iOS 5+,orgin设置为Default Origin,内存管理设置为 ARC, 以下图所示:
PaintCode code settings
如今把全部代码复制粘贴到 drawRect:方法里。 这段代码可能很长,可是它是PaintCode早就为你准备好的了。

[objc]  view plain copy
  1.     //// General Declarations  
  2. CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();  
  3. CGContextRef context = UIGraphicsGetCurrentContext();  
  4. //// Color Declarations  
  5. UIColor* fillColor = [UIColor colorWithRed0.416 green0.416 blue0.416 alpha: 1];  
  6. UIColor* strokeColor = [UIColor colorWithRed0.322 green0.322 blue0.322 alpha: 1];  
  7. UIColor* shadowColor2 = [UIColor colorWithRed0.2 green0.2 blue0.2 alpha: 1];  
  8. UIColor* shadowColor3 = [UIColor colorWithRed0.671 green0.671 blue0.671 alpha: 1];  
  9. UIColor* fillColor2 = [UIColor colorWithRed0.247 green0.247 blue0.247 alpha: 1];  
  10. UIColor* strokeColor2 = [UIColor colorWithRed0.188 green0.188 blue0.188 alpha: 1];  
  11. UIColor* color = [UIColor colorWithRed0 green0.886 blue0 alpha: 1];  
  12. //// Gradient Declarations  
  13. NSArray* outerRectGradientColors = [NSArray arrayWithObjects:   
  14.     (id)strokeColor.CGColor,   
  15.     (id)fillColor.CGColor, nil nil];  
  16. CGFloat outerRectGradientLocations[] = {01};  
  17. CGGradientRef outerRectGradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)outerRectGradientColors, outerRectGradientLocations);  
  18. NSArray* gradientColors = [NSArray arrayWithObjects:   
  19.     (id)strokeColor2.CGColor,   
  20.     (id)fillColor2.CGColor, nil nil];  
  21. CGFloat gradientLocations[] = {01};  
  22. CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);  
  23. //// Shadow Declarations  
  24. UIColor* darkShadow = shadowColor2;  
  25. CGSize darkShadowOffset = CGSizeMake(3.13.1);  
  26. CGFloat darkShadowBlurRadius = 5;  
  27. UIColor* lightShadow = shadowColor3;  
  28. CGSize lightShadowOffset = CGSizeMake(3.13.1);  
  29. CGFloat lightShadowBlurRadius = 5;  
  30. //// Frames  
  31. CGRect progressIndicatorFrame = CGRectMake(-1032147);  
  32. //// Subframes  
  33. CGRect group = CGRectMake(CGRectGetMinX(progressIndicatorFrame) + 10, CGRectGetMinY(progressIndicatorFrame) + 9, CGRectGetWidth(progressIndicatorFrame) - 2520);  
  34. CGRect activeProgressFrame = CGRectMake(CGRectGetMinX(group) + floor(CGRectGetWidth(group) * 0.00000 + 0.5), CGRectGetMinY(group) + floor(CGRectGetHeight(group) * 0.00000 + 0.5), floor(CGRectGetWidth(group) * 1.00000 + 0.5) - floor(CGRectGetWidth(group) * 0.00000 + 0.5), floor(CGRectGetHeight(group) * 1.00000 + 0.5) - floor(CGRectGetHeight(group) * 0.00000 + 0.5));  
  35. //// Abstracted Attributes  
  36. CGRect progressTrackActiveRect = CGRectMake(CGRectGetMinX(activeProgressFrame) + 4, CGRectGetMinY(activeProgressFrame) + 5, CGRectGetWidth(activeProgressFrame) - 810);  
  37. //// Progress Bar  
  38. {  
  39.     //// Border Drawing  
  40.     CGRect borderRect = CGRectMake(CGRectGetMinX(progressIndicatorFrame) + 2, CGRectGetMinY(progressIndicatorFrame) + 3, CGRectGetWidth(progressIndicatorFrame) - 534);  
  41.     UIBezierPath* borderPath = [UIBezierPath bezierPathWithRoundedRect: borderRect cornerRadius: 4];  
  42.     CGContextSaveGState(context);  
  43.     CGContextSetShadowWithColor(context, darkShadowOffset, darkShadowBlurRadius, darkShadow.CGColor);  
  44.     CGContextBeginTransparencyLayer(context, NULL);  
  45.     [borderPath addClip];  
  46.     CGContextDrawLinearGradient(context, outerRectGradient,  
  47.         CGPointMake(CGRectGetMidX(borderRect), CGRectGetMinY(borderRect)),  
  48.         CGPointMake(CGRectGetMidX(borderRect), CGRectGetMaxY(borderRect)),  
  49.         0);  
  50.     CGContextEndTransparencyLayer(context);  
  51.     ////// Border Inner Shadow  
  52.     CGRect borderBorderRect = CGRectInset([borderPath bounds], -lightShadowBlurRadius, -lightShadowBlurRadius);  
  53.     borderBorderRect = CGRectOffset(borderBorderRect, -lightShadowOffset.width, -lightShadowOffset.height);  
  54.     borderBorderRect = CGRectInset(CGRectUnion(borderBorderRect, [borderPath bounds]), -1, -1);  
  55.     UIBezierPath* borderNegativePath = [UIBezierPath bezierPathWithRect: borderBorderRect];  
  56.     [borderNegativePath appendPath: borderPath];  
  57.     borderNegativePath.usesEvenOddFillRule = YES;  
  58.     CGContextSaveGState(context);  
  59.     {  
  60.         CGFloat xOffset = lightShadowOffset.width + round(borderBorderRect.size.width);  
  61.         CGFloat yOffset = lightShadowOffset.height;  
  62.         CGContextSetShadowWithColor(context,  
  63.             CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),  
  64.             lightShadowBlurRadius,  
  65.             lightShadow.CGColor);  
  66.         [borderPath addClip];  
  67.         CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(borderBorderRect.size.width), 0);  
  68.         [borderNegativePath applyTransform: transform];  
  69.         [[UIColor grayColor] setFill];  
  70.         [borderNegativePath fill];  
  71.     }  
  72.     CGContextRestoreGState(context);  
  73.     CGContextRestoreGState(context);  
  74.    
  75.     //// ProgressTrack Drawing  
  76.     CGRect progressTrackRect = CGRectMake(CGRectGetMinX(progressIndicatorFrame) + 12, CGRectGetMinY(progressIndicatorFrame) + 12, CGRectGetWidth(progressIndicatorFrame) - 2914);  
  77.     UIBezierPath* progressTrackPath = [UIBezierPath bezierPathWithRoundedRect: progressTrackRect cornerRadius: 7];  
  78.     CGContextSaveGState(context);  
  79.     CGContextSetShadowWithColor(context, lightShadowOffset, lightShadowBlurRadius, lightShadow.CGColor);  
  80.     CGContextBeginTransparencyLayer(context, NULL);  
  81.     [progressTrackPath addClip];  
  82.     CGContextDrawLinearGradient(context, gradient,  
  83.         CGPointMake(CGRectGetMidX(progressTrackRect), CGRectGetMinY(progressTrackRect)),  
  84.         CGPointMake(CGRectGetMidX(progressTrackRect), CGRectGetMaxY(progressTrackRect)),  
  85.         0);  
  86.     CGContextEndTransparencyLayer(context);  
  87.     ////// ProgressTrack Inner Shadow  
  88.     CGRect progressTrackBorderRect = CGRectInset([progressTrackPath bounds], -darkShadowBlurRadius, -darkShadowBlurRadius);  
  89.     progressTrackBorderRect = CGRectOffset(progressTrackBorderRect, -darkShadowOffset.width, -darkShadowOffset.height);  
  90.     progressTrackBorderRect = CGRectInset(CGRectUnion(progressTrackBorderRect, [progressTrackPath bounds]), -1, -1);  
  91.     UIBezierPath* progressTrackNegativePath = [UIBezierPath bezierPathWithRect: progressTrackBorderRect];  
  92.     [progressTrackNegativePath appendPath: progressTrackPath];  
  93.     progressTrackNegativePath.usesEvenOddFillRule = YES;  
  94.     CGContextSaveGState(context);  
  95.     {  
  96.         CGFloat xOffset = darkShadowOffset.width + round(progressTrackBorderRect.size.width);  
  97.         CGFloat yOffset = darkShadowOffset.height;  
  98.         CGContextSetShadowWithColor(context,  
  99.             CGSizeMake(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset)),  
  100.             darkShadowBlurRadius,  
  101.             darkShadow.CGColor);  
  102.         [progressTrackPath addClip];  
  103.         CGAffineTransform transform = CGAffineTransformMakeTranslation(-round(progressTrackBorderRect.size.width), 0);  
  104.         [progressTrackNegativePath applyTransform: transform];  
  105.         [[UIColor grayColor] setFill];  
  106.         [progressTrackNegativePath fill];  
  107.     }  
  108.     CGContextRestoreGState(context);  
  109.     CGContextRestoreGState(context);  
  110.    
  111.     //// Group  
  112.     {  
  113.         //// ProgressTrackActive Drawing  
  114.         UIBezierPath* progressTrackActivePath = [UIBezierPath bezierPathWithRoundedRect: progressTrackActiveRect cornerRadius: 5];  
  115.         [color setFill];  
  116.         [progressTrackActivePath fill];  
  117.     }  
  118. }  
  119. //// Cleanup  
  120. CGGradientRelease(outerRectGradient);  
  121. CGGradientRelease(gradient);  
  122. CGColorSpaceRelease(colorSpace);  

注意: 你的代码可能看起来和上面的有一些不同,这取决于每一个人在画图的时候的细节,这没啥关系。

这里咱们能够明显看到PaintCode给咱们作了多少工做。你们能够想象若是一行一行的去写会用多少时间!可是若是这是你的爱好,固然没有关系— 可是大部分应该会更想花时间在编写一些更有趣的代码上吧! :]
代码前部分是 colors, gradients, 和 shadows的申明。 接着是frame的申明。 这里会有一个 progressTrackActiveRect 在//// Abstracted Attributes 代码段里, 他是用来控制进度条绿色部分的进度的, 工做原理和 UIProgressView 同样。
接下来 Progress Bar 代码段是用来绘制整个进度条的边框,进度槽,以及其余的部分,而后另外一个代码段是管理 ProgressActiveGroup的。 最后就是一些收尾代码。

注意: 这篇教程并不会去深刻的讲解 Core Graphics绘制。 咱们使用PaintCode的缘由就是让你们可以在不了解CoreGraphic状况下去建立更多的炫酷的控件。这让你们可以花更多时间在开发和调试上,而不是在这里慢慢的画画。

可是,了解一点点Core Graphics 知识能让你们更好的去认识PaintCode生成的代码,也一样可让你们去修改这些代码。 要想了解更多 Core Graphics, 请查看咱们的些列教程 Core Graphics tutorial series!

 

显示进度条

如今咱们的进度条已经准备好了,接下来的第一个测试就是看它是否能显示出来。
在xcode里找到 ResourcesStoryboardsMainStoryboard.storyboard ,而后打开它。 选择 Progress View Controller scene 而后从Object Library添加一个 View 进去。在Identity Inspector 里改变这个view的class为ProgressView, 而后在 Size Inspector里面把它的属性改成以下:

  • X: 20
  • Y: 183
  • Width: 280
  • Height: 46

Progress view size inspector
最后把这个项目运行一次。咱们的进度条应该和下面同样:
Progress bar first run
虽然进度条看起来已经不错了 — 可是他并无按照storyboard里view的大小绘制出来,要解决这个问题,咱们继续回到 ProgressView.m里的 drawRect: 找到下面这行:

[objc]  view plain copy
  1. …  
  2. //// Frames  
  3. CGRect progressIndicatorFrame = CGRectMake(2131834);  
  4. ...  

把它改为下面的这句:

[objc]  view plain copy
  1. - (void)drawRect:(CGRect)rect  
  2. {  
  3.     ...  
  4.     // Frames  
  5.     CGRect progressIndicatorFrame = rect;  
  6.     ...  
  7. }  

这句是让进度条的大小和咱们在storyboard里设置的view的大小同样。
再编译运行一次,进度条就应该和storyboard里的veiw同样大小了:
Progress bar frame fixed
如今进度条已经能正确的显示出来了,接下来咱们要作的就是让他动起来。

让进度条动起来

打开 ProgressViewController.m 在 @implementation 以前加入下面的代码:

[objc]  view plain copy
  1. // 1  
  2. #import "ProgressView.h"  
  3. #import "ProgressViewController.h"  
  4. // 2  
  5. #define kSecondsForCompleteUpdate   3.0  
  6. #define kUpdateInterval             0.02  
  7. // 3  
  8. @interface  ProgressViewController ()  
  9. @property (weak, nonatomic) IBOutlet ProgressView *progressView;  
  10. @property (weak, nonatomic) IBOutlet UIButton *startProgressButton;  
  11. @property (strongnonatomicNSTimer *timer;  
  12. @end  

咱们如今来看看上面的代码作了什么:

  1. 引入 ProgressView.h 头文件,这样在view controller里就能够引用它。
  2. 定义了2个常量 kSecondsForCompleteUpdate 和 kUpdateInterval 并给他们赋值。 用它们来控制着进度条的行为。
  3. 增长了一个类的Extension 而且为 UIButton 和 UIProgressView申明了带xib链接口的属性, 以及一个定时器用来更新进度条的 progress属性.

接着添加下面的代码 (任然在 ProgressViewController.m里):

[objc]  view plain copy
  1. -(IBAction)startProgressTapped {  
  2.     self.progressView.progress = 0.0;  
  3.    
  4.     self.startProgressButton.enabled = NO;  
  5.    
  6.     self.timer = [NSTimer timerWithTimeInterval:kUpdateInterval  
  7.                                          target:self  
  8.                                        selector:@selector(updateProgressView)  
  9.                                        userInfo:nil  
  10.                                         repeats:YES];  
  11.    
  12.     [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];  
  13.    
  14.     [self.timer fire];  
  15. }  

当屏幕上的按钮被点击时,这段代码将被调用。 首先先把进度条的 progress属性设置为 0。而后将按钮禁用掉,这样在进度条动画进行的时候咱们将不能再次点击按钮。 而后,建立一个定时器,用来控制动画的进行时长。
最后, 把定时器加进run loop来启动定时器-模拟事件的开始。
让咱们来看看self.timer 这行代码。 你们会发现定事情调用了 updateProgressView这个方法,这是用来更新进度条的进度的。 咱们立刻加加入这段代码,
把下面这段加入 ProgressViewController.m中:

[objc]  view plain copy
  1. -(void)updateProgressView; {  
  2.     if (self.progressView.progress < 1.0) {  
  3.         self.progressView.progress += (kUpdateInterval / kSecondsForCompleteUpdate);  
  4.     } else {  
  5.         [self.timer invalidate];  
  6.         self.startProgressButton.enabled = YES;  
  7.     }  
  8. }  

这段代码会检查progress属性是否还小于1, 也就是尚未完成。 若是还没完成,逐步的增长进度, 用前面定义2个常量来控制进度条增长的速率。
若是进度条的progress大于1了,也就是他100%完成了, 咱们会把定时器禁用掉,而后恢复按钮来让咱们可以再次模拟进度条增长。
如今咱们剩下的就是添加一个按钮来触发 startProgressTapped方法,让咱们能开始模拟整个测试了。

加入开始按钮

回到storyboard而后建立一个 Round Rect Button 放在 Progress View Controller 里面。 在 Attributes Inspector 里面把它的 title 改为 “Start Progress” 选择 Touch Up Inside 把他和代码里的 startProgressTapped链接起来。
而后修改按钮属性,在 Size Inspector里,应该和下图同样:

  • X: 97
  • Y: 20
  • Width: 128
  • Height: 44
  • Autosizing: 左上右固定间隙,固定宽。 可变的下间隙,和可变的高。

Button size attributes
接下来,连接代码里的按钮和进度条。 你的连接应该和下面同样:
Progress controller connections
编译运行一次项目,而后点击 Start Progress 按钮。咱们的进度条应该就和下图同样了:
Testing progress with button
Umm…进度条竟然没有动! 点了按钮之后啥都没发生!!怎么破!

更新进度条

问题出在,在 ProgressView 里面没有代码去更新进度槽。这玩意儿仍然是静态的被显示着,就像在PaintCode里同样。 咱们须要增长一些代码,来让进度条能够基于本身的 progress属性来绘制。
换到 ProgressView.m文件里.。找到下面这段:

[objc]  view plain copy
  1. …  
  2. //// Abstracted Attributes  
  3. CGRect progressTrackActiveRect = CGRectMake(CGRectGetMinX(activeProgressFrame) + 2, CGRectGetMinY(activeProgressFrame) + 2, CGRectGetWidth(activeProgressFrame) - 410);  
  4. …  

用下面的代码替换掉整个 CGRect progressTrackActiveRect这行:

[objc]  view plain copy
  1. CGRect progressTrackActiveRect = CGRectMake(CGRectGetMinX(activeProgressFrame) + 3,  
  2.                                                 CGRectGetMinY(activeProgressFrame) + 2,  
  3.                                                 (CGRectGetWidth(activeProgressFrame) - 4) * self.progress,  
  4.                                                 10);  

新的代码会基于进度条的 progress 属性去改变它的rect的宽。
最后一件事 —设置进度条的progress 为0。 这样在程序启动的时候,进度条就能和咱们但愿的同样处于0的位置。
回到 ProgressViewController.m 文件加入下面的代码:

[objc]  view plain copy
  1. -(void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.    
  4.     self.progressView.progress = 0.0;  
  5. }  

在跑一次程序,点击按钮。 咱们的的进度条应该开始逐步的填满整个进度槽了。
Final project
如今咱们完成了能够动态更新的进度条了。 他能够用来模拟3秒钟的后台任务或者下载任务。

总结

你能够在这里下载完整的PaintCode和XCode项目。
恭喜你们 – 在这个过程当中使用PaintCode制做了一个自定义的进度条,而且把它集成进了本身的项目中,相信你们必定学到了很多。
有了这个新技术,你们能够想怎么作怎么作,随意的去自定义本身的进度条 – 甚至是iOS7里的扁平进度条 :]
咱们还有好消息 – 更多的教程会陆续而!在第三部分教程里,咱们将会教你如何去用bezier路径画出一个箭头,并把它使用在一个简单的游戏里。


原帖:http://www.raywenderlich.com/35720/paintcode-tutorial-custom-progress-bar

相关文章
相关标签/搜索