文档章节

PaintCode 教程2:自定义进度条

S
 Snaiper
发布于 2016/01/14 14:36
字数 5302
阅读 135
收藏 0

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

踏出第一步

在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 的属性为如下:

  • 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

注意: 如果以后需要修改PaintCode里的 gradients, colors, 或者 shadows, 大家可以再左边栏下面的 panel 里点击对应的名字的 tab 去修改已命名的属性. 双击需要修改的属性的名字,然后在弹出的dialog里做修改就好了.

现在我们先关掉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
到此为止,进度条的基本外边已经完成, 我们接下来要开始做的是进度槽.

制作进度槽和背景

再找到 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工具,再拖一个矩形并且把它的属性设置为如下:

  • 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

© 著作权归作者所有

S
粉丝 13
博文 100
码字总数 135194
作品 0
深圳
私信 提问
创建一个跟分辨率无关的 iOS 8 应用

自从iOS退出依赖,png就被用来制作图标。这已经是如此简单了,那为什么还会有人会要考虑其他的解决方案呢? 一般的制作图标的工作流程是这样的:“我想要新添加一个按钮,这个action需要一个...

oschina
2014/09/11
4K
9
iOS app旧貌换新颜(一)—Launch Page让Logo"飞"出屏幕

前言 当今是个看脸的世界,一个app的颜值可能会决定用户的使用次数,icon的颜值更可能决定了用户是否回去下载,如果太丑,放在手机桌面都难看,那用户很可能就直接卸载了。所以漂亮的界面UI ...

一缕殇流化隐半边冰霜
2016/05/25
0
0
PaintCode 2.3 发布,支持 SVG 导出

PaintCode 2.3 发布,此版本包括 15 个新特性: SVG 代码生成 PDF, AI 和 EPS 导出 完整重建图片导出 动态序列导出 支持从 Sketch,Illustrator,Pages 复制和粘贴 Shapes & Groups 浏览器提...

oschina
2015/04/16
1K
0
iOS开发者必备:九大设计类工具

“工欲善其事,必先利其器”,对于iOS开发者和设计师来说,若在开发和设计的过程中有“利器”在手,那或许将会起到事半功倍的效果。现在,就让我们盘点下,当下最为流行和实用的iOS设计类开发...

沉淀岁月
2013/09/12
313
0
PaintCode 教程1:动态绘制按钮

PaintCode 是一个能够让你像Photoshop一样去设计你的用户界面的软件 – 但是它并不是仅仅保存一张图片当作资源让你来使用,它能够为你生成 CoreGraphic 源码直接使用到View的绘制中. 可以简单...

Snaiper
2016/01/14
31
0

没有更多内容

加载失败,请刷新页面

加载更多

浅谈prototype原型模式

一、原型模式简介 原型(Prototype)模式是一种对象创建型模式,他采取复制原型对象的方法来创建对象的实例。使用原型模式创建的实例,具有与原型一样的数据。 原型模式的特点: 1、由原型对...

青衣霓裳
28分钟前
8
0
shell mysql 备份

#!/bin/bash time2=$(date "+%Y-%m-%d-%H:%M:%S") /usr/local/mysql/bin/mysqldump -uroot -p ad > /usr/local/mysql/backup/"$time2".sql 变量引用原来是这么用的。......

奋斗的小牛
36分钟前
4
0
Jmeter监控Linux服务器操作

系统:Win7 64位 工具:Jmeter 4.0 要准备好的插件:JMeterPlugins-Standard-1.4.0,ServerAgent-2.2.1 解压JMeterPlugins-Standard-1.4.0.zip,将其中\lib\ext\JMeterPlugins-Standard.jar......

魔鬼妹子
36分钟前
5
0
系列文章:云原生Kubernetes日志落地方案

在Logging这块做了几年,最近1年来越来越多的同学来咨询如何为Kubernetes构建一个日志系统或者是来求助在这过程中遇到一系列问题如何解决,授人以鱼不如授人以渔,于是想把我们这些年积累的经...

Mr_zebra
36分钟前
5
0
入门必备!快速学会用Aspose.Words在表格中插入和删除列!

Aspose.Words For .Net(点击下载)是一种高级Word文档处理API,用于执行各种文档管理和操作任务。API支持生成,修改,转换,呈现和打印文档,而无需在跨平台应用程序中直接使用Microsoft W...

mnrssj
41分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部