├── .gitignore ├── Images ├── app_store_download_button.gif ├── app_store_download_button_in_motion.gif ├── app_store_download_finish.png ├── app_store_download_middle.png ├── app_store_download_start.png ├── dimming_view.gif ├── progress_view.gif ├── rounded_rect.png ├── shapes_logo.png └── voice_memos_record_button.gif ├── LICENSE ├── README.md ├── Shapes.podspec ├── Shapes ├── CAShapeLayer+UIBezierPath.h ├── CAShapeLayer+UIBezierPath.m ├── CATransaction+AnimateWithDuration.h ├── CATransaction+AnimateWithDuration.m ├── DTAnimatableShapeLayer.h ├── DTAnimatableShapeLayer.m ├── DTDimmingView.h ├── DTDimmingView.m ├── DTGraphicsConverter.h ├── DTGraphicsConverter.m ├── DTProgressView.h ├── DTProgressView.m ├── DTShapeButton.h ├── DTShapeButton.m ├── DTShapeView.h ├── DTShapeView.m └── Shapes.h └── ShapesExample ├── Rakefile ├── ShapeKitExample ├── AppDelegate.h ├── AppDelegate.m ├── Controllers │ ├── DimmingViewController.h │ ├── DimmingViewController.m │ ├── DownloadButtonViewController.h │ ├── DownloadButtonViewController.m │ ├── ProgressViewController.h │ ├── ProgressViewController.m │ ├── VoiceMemosRecordButtonViewController.h │ ├── VoiceMemosRecordButtonViewController.m │ └── cat_selfie.png ├── Controls │ ├── DimmableShapeButton.h │ ├── DimmableShapeButton.m │ ├── HighlightableShapeButton.h │ └── HighlightableShapeButton.m ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── LaunchImage.launchimage │ │ └── Contents.json │ └── cat_selfie.imageset │ │ ├── Contents.json │ │ └── cat_selfie.png ├── ShapesExample-Info.plist ├── ShapesExample-Prefix.pch ├── ShapesExample.storyboard ├── en.lproj │ └── InfoPlist.strings └── main.m ├── ShapeKitExampleTests ├── ShapesExampleTests-Info.plist ├── Specs │ └── ShapedView │ │ ├── ShapedViewGettersAndSettersTestCase.m │ │ └── ShapedViewPathTestCase.m └── en.lproj │ └── InfoPlist.strings └── ShapesExample.xcodeproj ├── project.pbxproj └── xcshareddata └── xcschemes ├── ShapesExample.xcscheme └── ShapesTests.xcscheme /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.moved-aside 14 | DerivedData 15 | .idea/ 16 | *.hmap 17 | *.xccheckout 18 | 19 | #CocoaPods 20 | Pods 21 | Podfile.lock 22 | *.xcworkspace -------------------------------------------------------------------------------- /Images/app_store_download_button.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/app_store_download_button.gif -------------------------------------------------------------------------------- /Images/app_store_download_button_in_motion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/app_store_download_button_in_motion.gif -------------------------------------------------------------------------------- /Images/app_store_download_finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/app_store_download_finish.png -------------------------------------------------------------------------------- /Images/app_store_download_middle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/app_store_download_middle.png -------------------------------------------------------------------------------- /Images/app_store_download_start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/app_store_download_start.png -------------------------------------------------------------------------------- /Images/dimming_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/dimming_view.gif -------------------------------------------------------------------------------- /Images/progress_view.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/progress_view.gif -------------------------------------------------------------------------------- /Images/rounded_rect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/rounded_rect.png -------------------------------------------------------------------------------- /Images/shapes_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/shapes_logo.png -------------------------------------------------------------------------------- /Images/voice_memos_record_button.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/Images/voice_memos_record_button.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Denys Telezhkin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![CocoaPod platform](https://cocoapod-badges.herokuapp.com/p/Shapes/badge.png)   2 | ![CocoaPod version](https://cocoapod-badges.herokuapp.com/v/Shapes/badge.png)   3 | ![License MIT](https://go-shields.herokuapp.com/license-MIT-blue.png) 4 | 5 | ![](Images/shapes_logo.png) 6 | 7 | Shapes is a set of wrappers around CAShapeLayer and UIBezierPath, that allows drawing and animating geometrically shaped views on iOS. Read more about it on the blog: http://mlsdev.com/blog/23 8 | 9 | ![](Images/progress_view.gif) 10 | ![](Images/dimming_view.gif) 11 | 12 | ![](Images/app_store_download_button.gif) 13 | ![](Images/voice_memos_record_button.gif) 14 | 15 | ### Shaped views 16 | 17 | `DTShapeView` is a UIView subclass, that is backed by CAShapeLayer instead of CALayer. It provides API for changing CAShapeLayer path, fill and stroke colors and other layer properties, basically allowing UIView to behave like geometric shape. 18 | 19 | All `DTShapeView` properties are automatically converted to CAShapeLayer properties or use CAShapeLayer properties directly. You can use whatever style you like, but we recommend using UIBezierPath and `DTShapeView` properties, because this allows you to completely bypass CoreFoundation objects. It also allows you to use CoreGraphics API instead of QuartzCore. 20 | 21 | `DTShapeView` fully supports both explicit and implicit animation and hit testing inside it's path. 22 | 23 | ### Progress views 24 | 25 | `DTProgressView` is a `DTShapeView` subclass, that allow animating progress views of any shape. `DTProgressView` uses `DTShapeView` path as track. 26 | 27 | By default, `DTProgressView` fills entire view bounds, filling view from left to right. And all you need to create a progress view, is drop it onto your view, set strokeColor and your progress view is ready! 28 | 29 | ```objective-c 30 | self.simpleProgressView.strokeColor = [UIColor greenColor]; 31 | ``` 32 | 33 | Whenever your progress changes, simply call 34 | 35 | ```objective-c 36 | [self.simpleProgressView setProgress:progress animated:YES]; 37 | ``` 38 | 39 | And progress change will be animated. `DTProgressView` supports any geometric shape UIBezierPath can define, and allows customizing animation duration and animation function. 40 | 41 | ### Dimming views 42 | 43 | `DTDimmingView` allows dimming part of the view, by "cutting" visible path from it. By default, dimming path contains entire UIView bounds. Create UIBezierPath, that describes, which part of the view should be visible, and set it on `DTDimmingView` instance to allow content to be seen. 44 | 45 | ```objective-c 46 | UIBezierPath * roundedPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.view.bounds, 100, 100)]; 47 | self.dimmingDynamicView.visiblePath = roundedPath; 48 | ``` 49 | 50 | ### Shaped buttons 51 | 52 | `DTShapeButton` is a UIButton, that has `DTShapedView` added as a subview. As a result, it allows manipulating UIButton shape and visual appearance by changing `DTShapedView` properties. By default, button shape is a rectangle with UIButton bounds set as it's frame. For example, drawing initial state of AppStore download button looks like this: 53 | 54 | ```objective-c 55 | self.downloadButton.shape.path = [UIBezierPath bezierPathWithRoundedRect:self.downloadButton.bounds cornerRadius:5.0f]; 56 | ``` 57 | 58 | To find out more about how animating between shapes works, read [Animatable buttons with Shapes tutorial](https://github.com/DenHeadless/Shapes/wiki/Building-animatable-buttons-with-Shapes) 59 | 60 | ## Examples 61 | 62 | Take a look at example project, provided in ShapesExample folder. 63 | 64 | ## Requirements 65 | 66 | * iOS 7,8,9 67 | * ARC 68 | * XCode 7 and iOS 9 SDK 69 | 70 | ## Installation 71 | 72 | Using CocoaPods: 73 | ```bash 74 | pod 'Shapes', '~> 1.0.2' 75 | ``` 76 | 77 | ## About MLSDev 78 | 79 | [MLSDev.com][mlsdev] 80 | 81 | Development Standards are maintained by MLSDev, Inc. We specialize in providing all-in-one solution in mobile and web development. Our team follows Lean principles and works according to agile methodologies to deliver the best results reducing the budget for development and its timeline. 82 | 83 | Find out more [here][mlsdev] and don't hesitate to [contact us][contact]! 84 | 85 | [mlsdev]: http://mlsdev.com 86 | [contact]: http://mlsdev.com/contact_us 87 | -------------------------------------------------------------------------------- /Shapes.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = "Shapes" 4 | s.version = "1.0.2" 5 | s.summary = "Framework for drawing and animating shaped views on iOS" 6 | 7 | s.homepage = "https://github.com/DenHeadless/Shapes" 8 | s.screenshots = "https://github.com/DenHeadless/Shapes/raw/master/Images/progress_view.gif", "https://github.com/DenHeadless/Shapes/raw/master/Images/dimming_view.gif","https://github.com/DenHeadless/Shapes/raw/master/Images/app_store_download_button.gif", "https://github.com/DenHeadless/Shapes/raw/master/Images/voice_memos_record_button.gif" 9 | 10 | s.license = "MIT" 11 | 12 | s.author = { "Denys Telezhkin" => "denys.telezhkin@yandex.ru" } 13 | s.social_media_url = 'https://twitter.com/DTCoder' 14 | 15 | s.platform = :ios, "7.0" 16 | s.source = { :git => "https://github.com/DenHeadless/Shapes.git", :tag => s.version.to_s } 17 | 18 | s.source_files = "Shapes" 19 | 20 | s.frameworks = "UIKit", "Foundation", "QuartzCore" 21 | s.requires_arc = true 22 | end 23 | -------------------------------------------------------------------------------- /Shapes/CAShapeLayer+UIBezierPath.h: -------------------------------------------------------------------------------- 1 | // 2 | // CAShapeLayer+UIBezierPath.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 19.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | #if __has_feature(nullability) // Xcode 6.3+ 29 | #pragma clang assume_nonnull begin 30 | #else 31 | #define nullable 32 | #define __nullable 33 | #endif 34 | 35 | /** 36 | Category on `CAShapeLayer`, that allows setting and getting UIBezierPath on CAShapeLayer. 37 | */ 38 | @interface CAShapeLayer (UIBezierPath) 39 | 40 | /** 41 | Update CAShapeLayer with UIBezierPath. 42 | */ 43 | - (void)dt_updateWithBezierPath:(UIBezierPath *)path; 44 | 45 | /** 46 | Get UIBezierPath object, constructed from CAShapeLayer. 47 | */ 48 | - (UIBezierPath*)dt_bezierPath; 49 | 50 | @end 51 | 52 | #if __has_feature(nullability) 53 | #pragma clang assume_nonnull end 54 | #endif -------------------------------------------------------------------------------- /Shapes/CAShapeLayer+UIBezierPath.m: -------------------------------------------------------------------------------- 1 | // 2 | // CAShapeLayer+UIBezierPath.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 19.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "CAShapeLayer+UIBezierPath.h" 27 | #import "DTGraphicsConverter.h" 28 | 29 | @implementation CAShapeLayer (UIBezierPath) 30 | 31 | -(void)dt_updateWithBezierPath:(UIBezierPath *)path 32 | { 33 | self.path = [path CGPath]; 34 | self.lineWidth = path.lineWidth; 35 | self.miterLimit = path.miterLimit; 36 | 37 | self.lineCap = [DTGraphicsConverter lineCapFromCGLineCap:path.lineCapStyle]; 38 | self.lineJoin = [DTGraphicsConverter lineJoinFromCGLineJoin:path.lineJoinStyle]; 39 | 40 | self.fillRule = path.usesEvenOddFillRule ? kCAFillRuleEvenOdd : kCAFillRuleNonZero; 41 | 42 | NSInteger count; 43 | [path getLineDash:NULL count:&count phase:NULL]; 44 | CGFloat pattern[count], phase; 45 | [path getLineDash:pattern count:NULL phase:&phase]; 46 | 47 | NSMutableArray *lineDashPattern = [NSMutableArray array]; 48 | for (NSUInteger i = 0; i < count; i++) { 49 | [lineDashPattern addObject:@(pattern[i])]; 50 | } 51 | 52 | self.lineDashPattern = [lineDashPattern copy]; 53 | self.lineDashPhase = phase; 54 | } 55 | 56 | -(UIBezierPath *)dt_bezierPath 57 | { 58 | UIBezierPath * path = [UIBezierPath bezierPathWithCGPath:self.path]; 59 | path.lineWidth = self.lineWidth; 60 | path.miterLimit = self.miterLimit; 61 | 62 | path.lineCapStyle = [DTGraphicsConverter lineCapFromCALineCap:self.lineCap]; 63 | path.lineJoinStyle = [DTGraphicsConverter lineJoinFromCALineJoin:self.lineJoin]; 64 | 65 | path.usesEvenOddFillRule = (self.fillRule == kCAFillRuleEvenOdd); 66 | 67 | CGFloat phase = self.lineDashPhase; 68 | NSInteger count = self.lineDashPattern.count; 69 | CGFloat pattern[count]; 70 | for (NSUInteger i = 0; i < count; i++) { 71 | pattern[i] = [[self.lineDashPattern objectAtIndex:i] floatValue]; 72 | } 73 | [path setLineDash:pattern count:count phase:phase]; 74 | 75 | return path; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Shapes/CATransaction+AnimateWithDuration.h: -------------------------------------------------------------------------------- 1 | // 2 | // CATransaction+AnimateWithDuration.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 20.09.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #if __has_feature(nullability) // Xcode 6.3+ 12 | #pragma clang assume_nonnull begin 13 | #else 14 | #define nullable 15 | #define __nullable 16 | #endif 17 | 18 | @interface CATransaction (AnimateWithDuration) 19 | 20 | +(void)dt_animateWithDuration:(NSTimeInterval)duration 21 | animations:(nullable void (^)(void))animations 22 | completion:(nullable void (^)())completion; 23 | 24 | @end 25 | 26 | #if __has_feature(nullability) 27 | #pragma clang assume_nonnull end 28 | #endif 29 | -------------------------------------------------------------------------------- /Shapes/CATransaction+AnimateWithDuration.m: -------------------------------------------------------------------------------- 1 | // 2 | // CATransaction+AnimateWithDuration.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 20.09.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "CATransaction+AnimateWithDuration.h" 10 | 11 | @implementation CATransaction (AnimateWithDuration) 12 | 13 | +(void)dt_animateWithDuration:(NSTimeInterval)duration 14 | animations:(void (^)(void))animations 15 | completion:(void (^)())completion 16 | { 17 | [CATransaction begin]; 18 | [CATransaction setAnimationDuration:duration]; 19 | 20 | if (completion) 21 | { 22 | [CATransaction setCompletionBlock:completion]; 23 | } 24 | 25 | if (animations) 26 | { 27 | animations(); 28 | } 29 | [CATransaction commit]; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Shapes/DTAnimatableShapeLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTAnimatableShapeLayer.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 31.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | #if __has_feature(nullability) // Xcode 6.3+ 29 | #pragma clang assume_nonnull begin 30 | #else 31 | #define nullable 32 | #define __nullable 33 | #define null_resettable 34 | #endif 35 | 36 | /** 37 | `DTAnimatableShapeLayer` allows implicit animation of CAShapeLayer path. It uses CTTransaction animation duration and animation timing function to animate a change. 38 | */ 39 | 40 | @interface DTAnimatableShapeLayer : CAShapeLayer 41 | 42 | /** 43 | Set of all animatable properties on CAShapeLayer. By default, contains "path" key. Add properties to the set, if you wan't them to change with animation. 44 | 45 | To animate changes, use CATransaction, or provided CATransaction+AnimateWithDuration convenience category. 46 | */ 47 | @property (nonatomic, strong, null_resettable) NSMutableSet * animatableKeys; 48 | 49 | @end 50 | 51 | #if __has_feature(nullability) 52 | #pragma clang assume_nonnull end 53 | #endif -------------------------------------------------------------------------------- /Shapes/DTAnimatableShapeLayer.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTAnimatableShapeLayer.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 31.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTAnimatableShapeLayer.h" 27 | 28 | @implementation DTAnimatableShapeLayer 29 | 30 | -(NSMutableSet *)animatableKeys 31 | { 32 | if (!_animatableKeys) 33 | { 34 | _animatableKeys = [NSMutableSet setWithObject:@"path"]; 35 | } 36 | return _animatableKeys; 37 | } 38 | 39 | -(id)actionForKey:(NSString *)key 40 | { 41 | if ([self.animatableKeys containsObject:key]) 42 | { 43 | return [self customAnimationForKey:key]; 44 | } 45 | return [super actionForKey:key]; 46 | } 47 | 48 | - (CABasicAnimation *) customAnimationForKey: (NSString *) key 49 | { 50 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key]; 51 | animation.fromValue = [self.presentationLayer valueForKey:key]; 52 | animation.duration = [CATransaction animationDuration]; 53 | return animation; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Shapes/DTDimmingView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTDimmedView.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 23.07.14. 6 | // Copyright (c) 2014 MLSDev. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | #if __has_feature(nullability) // Xcode 6.3+ 29 | #pragma clang assume_nonnull begin 30 | #else 31 | #define nullable 32 | #define __nullable 33 | #endif 34 | 35 | /** 36 | `DTDimmingView` allows dimming part of the view, by "cutting" visible path from it. By default, dimming path contains entire UIView bounds. Create UIBezierPath, that describes, which part of the view should be visible, and set it on `DTDimmingView` instance to allow content to be seen. 37 | */ 38 | @interface DTDimmingView : UIView 39 | 40 | /** 41 | UIBezierPath, that describes, which part of the content should be visible. It must be completely inside dimmedPath for dimming to work. 42 | */ 43 | @property (nonatomic, strong, nullable) UIBezierPath * visiblePath; 44 | 45 | /** 46 | UIBezierPath, that describes, which part of the view should be dimmed. By default, entire view is dimmed. 47 | */ 48 | @property (nonatomic, strong, null_resettable) UIBezierPath * dimmedPath; 49 | 50 | /** 51 | Opacity for dimming view. 0.9 by default. 52 | */ 53 | @property (nonatomic, assign) float dimmingOpacity UI_APPEARANCE_SELECTOR; 54 | 55 | /** 56 | Color of a dimming view. [UIColor blackColor] by default. 57 | */ 58 | @property (nonatomic, strong, nullable) UIColor * dimmingColor UI_APPEARANCE_SELECTOR; 59 | 60 | @end 61 | 62 | #if __has_feature(nullability) 63 | #pragma clang assume_nonnull end 64 | #endif 65 | -------------------------------------------------------------------------------- /Shapes/DTDimmingView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTDimmedView.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 23.07.14. 6 | // Copyright (c) 2014 MLSDev. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTDimmingView.h" 27 | #import "CAShapeLayer+UIBezierPath.h" 28 | 29 | @interface DTDimmingView() 30 | @property (nonatomic, strong) CAShapeLayer * fillLayer; 31 | 32 | @end 33 | 34 | @implementation DTDimmingView 35 | 36 | @synthesize dimmedPath = _dimmedPath; 37 | 38 | #pragma mark - appearance 39 | 40 | +(void)load 41 | { 42 | [self.appearance setDimmingOpacity:0.9]; 43 | [self.appearance setDimmingColor:[UIColor blackColor]]; 44 | } 45 | 46 | #pragma mark - getters and setters 47 | 48 | -(UIBezierPath *)dimmedPath 49 | { 50 | if (!_dimmedPath) 51 | { 52 | _dimmedPath = [UIBezierPath bezierPathWithRect:self.bounds]; 53 | } 54 | return _dimmedPath; 55 | } 56 | 57 | -(void)setDimmedPath:(UIBezierPath *)dimmedPath 58 | { 59 | _dimmedPath = dimmedPath; 60 | [self updatePathsWithVisiblePath:self.visiblePath]; 61 | } 62 | 63 | -(void)setVisiblePath:(UIBezierPath *)visiblePath 64 | { 65 | _visiblePath = visiblePath; 66 | [self updatePathsWithVisiblePath:visiblePath]; 67 | } 68 | 69 | -(void)setDimmingColor:(UIColor *)dimmingColor 70 | { 71 | _dimmingColor = dimmingColor; 72 | [self updatePathsWithVisiblePath:self.visiblePath]; 73 | } 74 | 75 | #pragma mark - updating visible paths 76 | 77 | -(void)updatePathsWithVisiblePath:(UIBezierPath *)visiblePath 78 | { 79 | [self.fillLayer removeFromSuperlayer]; 80 | 81 | visiblePath.usesEvenOddFillRule = YES; 82 | 83 | UIBezierPath * dimmedPath = [UIBezierPath bezierPathWithCGPath:self.dimmedPath.CGPath]; 84 | 85 | [dimmedPath appendPath:visiblePath]; 86 | dimmedPath.usesEvenOddFillRule = YES; 87 | 88 | self.fillLayer = [CAShapeLayer layer]; 89 | self.fillLayer.path = dimmedPath.CGPath; 90 | self.fillLayer.fillRule = kCAFillRuleEvenOdd; 91 | self.fillLayer.fillColor = self.dimmingColor.CGColor; 92 | self.fillLayer.opacity = self.dimmingOpacity; 93 | 94 | [self.layer addSublayer:self.fillLayer]; 95 | } 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /Shapes/DTGraphicsConverter.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTGraphicsConverter.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 06.09.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | #if __has_feature(nullability) // Xcode 6.3+ 29 | #pragma clang assume_nonnull begin 30 | #else 31 | #define nullable 32 | #define __nullable 33 | #endif 34 | 35 | /** 36 | `DTGraphicsConverter` allows converting from CoreGraphics values to Quartz values and vice versa. 37 | */ 38 | 39 | @interface DTGraphicsConverter : NSObject 40 | 41 | /** 42 | Convert CALineCap string constant to CGLineCap value. 43 | */ 44 | +(CGLineCap)lineCapFromCALineCap:(NSString *)lineCap; 45 | 46 | /** 47 | Convert CALineJoin string constant to CGLineJoin value. 48 | */ 49 | +(CGLineJoin)lineJoinFromCALineJoin:(NSString *)lineJoin; 50 | 51 | /** 52 | Convert CGLineCap value to CALineCap string constant. 53 | */ 54 | +(NSString *)lineCapFromCGLineCap:(CGLineCap)lineCap; 55 | 56 | /** 57 | Convert CGLineJoin value to CALineCap string constant. 58 | */ 59 | +(NSString *)lineJoinFromCGLineJoin:(CGLineJoin)lineJoin; 60 | 61 | @end 62 | 63 | #if __has_feature(nullability) 64 | #pragma clang assume_nonnull end 65 | #endif 66 | -------------------------------------------------------------------------------- /Shapes/DTGraphicsConverter.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTGraphicsConverter.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 06.09.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTGraphicsConverter.h" 27 | 28 | @implementation DTGraphicsConverter 29 | 30 | +(NSDictionary *)CGtoCALineCaps 31 | { 32 | return @{ 33 | @(kCGLineCapSquare) :kCALineCapSquare, 34 | @(kCGLineCapButt) : kCALineCapButt, 35 | @(kCGLineCapRound) : kCALineCapRound 36 | }; 37 | } 38 | 39 | +(NSDictionary *)CGtoCALineJoins 40 | { 41 | return @{ 42 | @(kCGLineJoinRound) : kCALineJoinRound, 43 | @(kCGLineJoinMiter) : kCALineJoinMiter, 44 | @(kCGLineJoinBevel) : kCALineJoinBevel 45 | }; 46 | } 47 | 48 | +(NSDictionary *)CAtoCGLineCaps 49 | { 50 | return @{ 51 | kCALineCapSquare : @(kCGLineCapSquare), 52 | kCALineCapButt : @(kCGLineCapButt), 53 | kCALineCapRound : @(kCGLineCapRound) 54 | }; 55 | } 56 | 57 | +(NSDictionary *)CAtoCGLineJoins 58 | { 59 | return @{ 60 | kCALineJoinRound : @(kCGLineJoinRound), 61 | kCALineJoinMiter : @(kCGLineJoinMiter), 62 | kCALineJoinBevel : @(kCGLineJoinBevel) 63 | }; 64 | } 65 | 66 | +(NSString *)lineCapFromCGLineCap:(CGLineCap)lineCap 67 | { 68 | return [self CGtoCALineCaps][@(lineCap)]; 69 | } 70 | 71 | +(NSString *)lineJoinFromCGLineJoin:(CGLineJoin)lineJoin 72 | { 73 | return [self CGtoCALineJoins][@(lineJoin)]; 74 | } 75 | 76 | +(CGLineCap)lineCapFromCALineCap:(NSString *)lineCap 77 | { 78 | return [[self CAtoCGLineCaps][lineCap] intValue]; 79 | } 80 | 81 | +(CGLineJoin)lineJoinFromCALineJoin:(NSString *)lineJoin 82 | { 83 | return [[self CAtoCGLineJoins][lineJoin] intValue]; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /Shapes/DTProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTProgressView.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 17.07.14. 6 | // Copyright (c) 2014 MLSDev. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTShapeView.h" 27 | 28 | #if __has_feature(nullability) // Xcode 6.3+ 29 | #pragma clang assume_nonnull begin 30 | #else 31 | #define nullable 32 | #define __nullable 33 | #endif 34 | 35 | /** 36 | `DTProgressView` is a `DTShapeView` subclass, that allow animating progress views of any shape. `DTProgressView` uses `DTShapeView` path as track. Stroke start and stroke end properties provide ability to change progress state of a view. 37 | 38 | By default, progress view fills entire view frame, animating progress from left to right. 39 | */ 40 | @interface DTProgressView : DTShapeView 41 | 42 | /** 43 | `DTProgressView` progress. Value range from 0 to 1, 0 by default. 44 | */ 45 | @property (nonatomic, assign, readonly) IBInspectable float progress; 46 | 47 | /** 48 | Duration of an animated progress change. 49 | 50 | Default is 0.3s. 51 | */ 52 | @property (nonatomic, assign) NSTimeInterval animationDuration UI_APPEARANCE_SELECTOR; 53 | 54 | /** 55 | Animation function to use, when animating progress change. 56 | */ 57 | @property (nonatomic, strong, nullable) CAValueFunction * animationFunction; 58 | 59 | /** 60 | Set progress value. This method is an alias for setStrokeEnd:animated:. 61 | 62 | @param progress The new progress value. 63 | 64 | @param animated Specify YES to animate the change or NO if you do not want the change to be animated. 65 | */ 66 | - (void)setProgress:(float)progress animated:(BOOL)animated; 67 | 68 | /** 69 | Set stroke start value. 70 | 71 | @param progress The new progress value. 72 | 73 | @param animated Specify YES to animate the change or NO if you do not want the change to be animated. 74 | */ 75 | - (void)setStrokeStart:(float)start animated:(BOOL)animated; 76 | 77 | /** 78 | Set strokeEnd value. This method is an alias for setProgress:animated:. 79 | 80 | @param progress The new strokeEnd value. 81 | 82 | @param animated Specify YES to animate the change or NO if you do not want the change to be animated. 83 | */ 84 | - (void)setStrokeEnd:(float)end animated:(BOOL)animated; 85 | 86 | @end 87 | 88 | #if __has_feature(nullability) 89 | #pragma clang assume_nonnull end 90 | #endif 91 | -------------------------------------------------------------------------------- /Shapes/DTProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTProgressView.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 17.07.14. 6 | // Copyright (c) 2014 MLSDev. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | 27 | #import "DTProgressView.h" 28 | 29 | @interface DTProgressView() 30 | @end 31 | 32 | @implementation DTProgressView 33 | 34 | static NSString * const kStrokeEndAnimationKey = @"Stroke end animation"; 35 | static NSString * const kStrokeStartAnimationKey = @"Stroke start animation"; 36 | 37 | +(void)load 38 | { 39 | [self.appearance setAnimationDuration:0.3]; 40 | } 41 | 42 | -(void)commonSetup 43 | { 44 | UIBezierPath * path = [UIBezierPath bezierPath]; 45 | path.lineWidth = self.frame.size.height; 46 | [path moveToPoint:CGPointMake(0, self.frame.size.height/2)]; 47 | [path addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height/2)]; 48 | [self setPath:path]; 49 | 50 | [self setFillColor:[UIColor clearColor]]; 51 | self.strokeColor = [UIColor grayColor]; 52 | 53 | self.shapeLayer.strokeEnd = 0; 54 | self.shapeLayer.strokeStart = 0; 55 | } 56 | 57 | -(instancetype)initWithCoder:(NSCoder *)aDecoder 58 | { 59 | if (self=[super initWithCoder:aDecoder]) 60 | { 61 | [self commonSetup]; 62 | } 63 | return self; 64 | } 65 | 66 | -(instancetype)initWithFrame:(CGRect)frame 67 | { 68 | if (self = [super initWithFrame:frame]) 69 | { 70 | [self commonSetup]; 71 | } 72 | return self; 73 | } 74 | 75 | -(float)progress 76 | { 77 | return self.strokeEnd; 78 | } 79 | 80 | - (void)setProgress:(float)progress animated:(BOOL)animated 81 | { 82 | [self setStrokeEnd:progress animated:animated]; 83 | } 84 | 85 | -(float)normalizedProgressValueFromValue:(float)value 86 | { 87 | if (value>1) 88 | return 1; 89 | if (value<0) 90 | return 0; 91 | return value; 92 | } 93 | 94 | -(void)setStrokeStart:(float)strokeStart animated:(BOOL)animated 95 | { 96 | strokeStart = [self normalizedProgressValueFromValue:strokeStart]; 97 | 98 | if (animated) 99 | { 100 | [self animateStrokeStart:strokeStart]; 101 | } 102 | else { 103 | [self.layer removeAnimationForKey:kStrokeStartAnimationKey]; 104 | self.shapeLayer.strokeStart = strokeStart; 105 | self.strokeStart = strokeStart; 106 | } 107 | } 108 | 109 | -(void)setStrokeEnd:(float)end animated:(BOOL)animated 110 | { 111 | end = [self normalizedProgressValueFromValue:end]; 112 | 113 | if (animated) 114 | { 115 | [self animateStrokeEnd:end]; 116 | } 117 | else { 118 | [self.layer removeAnimationForKey:kStrokeEndAnimationKey]; 119 | self.shapeLayer.strokeEnd = end; 120 | self.strokeEnd = end; 121 | } 122 | } 123 | 124 | -(void)animateStrokeStart:(float)start 125 | { 126 | float fromValue = self.strokeStart; 127 | 128 | if ( [self.shapeLayer animationForKey:kStrokeStartAnimationKey]!=nil) 129 | { 130 | CAShapeLayer * presentationLayer = [self.shapeLayer presentationLayer]; 131 | fromValue = [presentationLayer strokeStart]; 132 | } 133 | 134 | [self.layer removeAnimationForKey:kStrokeStartAnimationKey]; 135 | 136 | self.shapeLayer.strokeStart = start; 137 | 138 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; 139 | animation.duration = self.animationDuration; 140 | animation.valueFunction = self.animationFunction; 141 | animation.fromValue = @(fromValue); 142 | animation.toValue = @(start); 143 | animation.removedOnCompletion = YES; 144 | 145 | [self.shapeLayer addAnimation:animation forKey:kStrokeStartAnimationKey]; 146 | self.strokeStart = start; 147 | } 148 | 149 | -(void)animateStrokeEnd:(float)end 150 | { 151 | float fromValue = self.strokeEnd; 152 | 153 | if ( [self.shapeLayer animationForKey:kStrokeEndAnimationKey]!=nil) 154 | { 155 | CAShapeLayer * presentationLayer = [self.shapeLayer presentationLayer]; 156 | fromValue = [presentationLayer strokeEnd]; 157 | } 158 | 159 | [self.layer removeAnimationForKey:kStrokeEndAnimationKey]; 160 | 161 | self.shapeLayer.strokeEnd = end; 162 | 163 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 164 | animation.duration = self.animationDuration; 165 | animation.valueFunction = self.animationFunction; 166 | animation.fromValue = @(fromValue); 167 | animation.toValue = @(end); 168 | animation.removedOnCompletion = YES; 169 | 170 | [self.shapeLayer addAnimation:animation forKey:kStrokeEndAnimationKey]; 171 | self.strokeEnd = end; 172 | } 173 | 174 | - (void)animateToProgress:(float)progress 175 | { 176 | progress = [self normalizedProgressValueFromValue:progress]; 177 | 178 | [self animateStrokeEnd:progress]; 179 | } 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /Shapes/DTShapeButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTShapeButton.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 30.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTShapeView.h" 27 | 28 | #if __has_feature(nullability) // Xcode 6.3+ 29 | #pragma clang assume_nonnull begin 30 | #else 31 | #define nullable 32 | #define __nullable 33 | #endif 34 | 35 | /** 36 | ` DTShapeButton` is a UIButton, that has `DTShapedView` added as a subview. As a result, it allows manipulating UIButton shape and visual appearance by changing `DTShapedView` properties. By default, button shape is a rectangle with UIButton bounds set as it's frame. 37 | */ 38 | @interface DTShapeButton : UIButton 39 | 40 | /** 41 | `DTShapeView`, added as a sublayer to UIButton's layer. 42 | */ 43 | @property (nonatomic, strong, nullable) DTShapeView * shape; 44 | 45 | @end 46 | 47 | #if __has_feature(nullability) 48 | #pragma clang assume_nonnull end 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /Shapes/DTShapeButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTShapeButton.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 30.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTShapeButton.h" 27 | 28 | @implementation DTShapeButton 29 | 30 | -(instancetype)initWithCoder:(NSCoder *)aDecoder 31 | { 32 | if (self = [super initWithCoder:aDecoder]) 33 | { 34 | [self commonSetup]; 35 | } 36 | return self; 37 | } 38 | 39 | -(instancetype)initWithFrame:(CGRect)frame 40 | { 41 | if (self = [super initWithFrame:frame]) 42 | { 43 | [self commonSetup]; 44 | } 45 | return self; 46 | } 47 | 48 | -(void)commonSetup 49 | { 50 | DTShapeView * buttonShape = [[DTShapeView alloc] initWithFrame:self.bounds]; 51 | UIBezierPath * path = [UIBezierPath bezierPathWithRect:self.bounds]; 52 | buttonShape.path = path; 53 | 54 | [self addSubview:buttonShape]; 55 | self.shape = buttonShape; 56 | self.shape.userInteractionEnabled = NO; 57 | self.shape.exclusiveTouch = NO; 58 | 59 | buttonShape.fillColor = [UIColor clearColor]; 60 | buttonShape.strokeColor = self.tintColor; 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Shapes/DTShapeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DTShapeView.h 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 17.07.14. 6 | // Copyright (c) 2014 MLSDev. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | #import "DTAnimatableShapeLayer.h" 29 | 30 | #if __has_feature(nullability) // Xcode 6.3+ 31 | #pragma clang assume_nonnull begin 32 | #else 33 | #define nullable 34 | #define __nullable 35 | #endif 36 | 37 | /** 38 | `DTShapeView` is a UIView subclass, that is backed by CAShapeLayer instead of CALayer. It provides API for changing CAShapeLayer path, fill and stroke colors and other layer properties, basically allowing UIView to behave like geometric shape. 39 | 40 | All `DTShapeView` properties are automatically converted to CAShapeLayer properties or use CAShapeLayer properties directly. You can use whatever style you like, but we recommend using UIBezierPath and `DTShapeView` properties, because this allows you to completely bypass CoreFoundation objects. It also allows you to use CoreGraphics API instead of QuartzCore. 41 | */ 42 | @interface DTShapeView : UIView 43 | 44 | /** 45 | Setting path property automatically converts all UIBezierPath properties to CAShapeLayer properties. 46 | */ 47 | @property (nonatomic, strong, nullable) UIBezierPath * path; 48 | 49 | /** 50 | CAShapeLayer, that is backing view. 51 | */ 52 | @property (nonatomic, strong, readonly) DTAnimatableShapeLayer * shapeLayer; 53 | 54 | /** 55 | Fill color, used by CAShapeLayer. UIColor is automatically converted to and from CAShapeLayer fillColor property. 56 | */ 57 | @property (nonatomic, strong) IBInspectable UIColor * fillColor; 58 | 59 | /** 60 | Stroke color, used by CAShapeLayer. UIColor is automatically converted to and from CAShapeLayer strokeColor property. 61 | */ 62 | @property (nonatomic, strong) IBInspectable UIColor * strokeColor; 63 | 64 | /** 65 | Fill rule, used by CAShapeLayer. Automatically converts to CAFillRule constant values on CAShapeLayer. 66 | */ 67 | @property (nonatomic, assign) IBInspectable BOOL usesEvenOddFillRule; 68 | 69 | /** 70 | Set CAShapeLayer strokeStart property. 71 | */ 72 | @property (nonatomic, assign) IBInspectable CGFloat strokeStart; 73 | 74 | /** 75 | Set CAShapeLayer strokeEnd property. 76 | */ 77 | @property (nonatomic, assign) IBInspectable CGFloat strokeEnd; 78 | 79 | /** 80 | This property uses CAShapeLayer lineWidth property directly. 81 | */ 82 | @property (nonatomic, assign) IBInspectable CGFloat lineWidth; 83 | 84 | /** 85 | This property uses CAShapeLayer miterLimit property directly. 86 | */ 87 | @property (nonatomic, assign) IBInspectable CGFloat miterLimit; 88 | 89 | /** 90 | This property is automatically converted to QuartzCore line cap constant values on CAShapeLayer. 91 | */ 92 | @property (nonatomic, assign) CGLineCap lineCap; 93 | 94 | /** 95 | This property is automatically converted to QuartzCore line join constant values on CAShapeLayer. 96 | */ 97 | @property (nonatomic, assign) CGLineJoin lineJoin; 98 | 99 | /** 100 | This property uses CAShapeLayer lineDashPhase property directly. 101 | */ 102 | @property (nonatomic, assign) CGFloat lineDashPhase; 103 | 104 | /** 105 | This property uses CAShapeLayer lineDashPattern property directly. 106 | */ 107 | @property (nonatomic, copy) NSArray *lineDashPattern; 108 | 109 | /** 110 | Set this property to YES, if you want to enable hit testing inside CAShapeLayer path. 111 | 112 | Default value is NO. 113 | */ 114 | @property (nonatomic, assign) BOOL hitTestInsidePath; 115 | 116 | @end 117 | 118 | #if __has_feature(nullability) 119 | #pragma clang assume_nonnull end 120 | #endif 121 | -------------------------------------------------------------------------------- /Shapes/DTShapeView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DTShapeView.m 3 | // Shapes 4 | // 5 | // Created by Denys Telezhkin on 17.07.14. 6 | // Copyright (c) 2014 MLSDev. All rights reserved. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "DTShapeView.h" 27 | #import "CAShapeLayer+UIBezierPath.h" 28 | #import "DTGraphicsConverter.h" 29 | #import "DTAnimatableShapeLayer.h" 30 | 31 | @implementation DTShapeView 32 | 33 | @dynamic strokeStart, strokeEnd, lineWidth, miterLimit, lineDashPhase, lineDashPattern; 34 | 35 | #pragma mark - UIView methods 36 | 37 | +(Class)layerClass 38 | { 39 | return [DTAnimatableShapeLayer class]; 40 | } 41 | 42 | -(CAShapeLayer *)shapeLayer 43 | { 44 | return (CAShapeLayer*)self.layer; 45 | } 46 | 47 | #pragma mark - method forwarding 48 | 49 | - (BOOL)shouldForwardSelector:(SEL)aSelector { 50 | return (![[[self.layer superclass] superclass] instancesRespondToSelector:aSelector] && 51 | [self.layer respondsToSelector:aSelector]); 52 | } 53 | 54 | - (id)forwardingTargetForSelector:(SEL)aSelector { 55 | return (![self respondsToSelector:aSelector] && [self shouldForwardSelector:aSelector]) ? self.layer : self; 56 | } 57 | 58 | #pragma mark - getters and setters 59 | 60 | -(void)setPath:(UIBezierPath *)path 61 | { 62 | _path = path; 63 | [CATransaction begin]; 64 | [CATransaction setAnimationDuration:[CATransaction animationDuration]]; 65 | [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ]; 66 | [self.shapeLayer dt_updateWithBezierPath:path]; 67 | [CATransaction commit]; 68 | } 69 | 70 | -(void)setFillColor:(UIColor *)fillColor 71 | { 72 | [self.shapeLayer setFillColor:[fillColor CGColor]]; 73 | } 74 | 75 | -(UIColor *)fillColor 76 | { 77 | return [UIColor colorWithCGColor:[self.shapeLayer fillColor]]; 78 | } 79 | 80 | -(UIColor *)strokeColor 81 | { 82 | return [UIColor colorWithCGColor:[self.shapeLayer strokeColor]]; 83 | } 84 | 85 | -(void)setStrokeColor:(UIColor *)strokeColor 86 | { 87 | [self.shapeLayer setStrokeColor:[strokeColor CGColor]]; 88 | } 89 | 90 | -(void)setUsesEvenOddFillRule:(BOOL)usesEvenOddFillRule 91 | { 92 | self.shapeLayer.fillRule = usesEvenOddFillRule ? kCAFillRuleEvenOdd : kCAFillRuleNonZero; 93 | } 94 | 95 | -(BOOL)usesEvenOddFillRule 96 | { 97 | return self.shapeLayer.fillRule == kCAFillRuleEvenOdd; 98 | } 99 | 100 | -(void)setLineCap:(CGLineCap)lineCap 101 | { 102 | self.shapeLayer.lineCap = [DTGraphicsConverter lineCapFromCGLineCap:lineCap]; 103 | } 104 | 105 | -(CGLineCap)lineCap 106 | { 107 | return [DTGraphicsConverter lineCapFromCALineCap:self.shapeLayer.lineCap]; 108 | } 109 | 110 | -(void)setLineJoin:(CGLineJoin)lineJoin 111 | { 112 | self.shapeLayer.lineJoin = [DTGraphicsConverter lineJoinFromCGLineJoin:lineJoin]; 113 | } 114 | 115 | -(CGLineJoin)lineJoin 116 | { 117 | return [DTGraphicsConverter lineJoinFromCALineJoin:self.shapeLayer.lineJoin]; 118 | } 119 | 120 | #pragma mark - hit testing 121 | 122 | - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { 123 | BOOL inside = [super pointInside:point withEvent:event]; 124 | return self.hitTestInsidePath ? [self.path containsPoint:point] && inside : inside; 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /Shapes/Shapes.h: -------------------------------------------------------------------------------- 1 | // 2 | // Shapes.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 20.09.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "DTShapeView.h" 10 | #import "DTShapeButton.h" 11 | 12 | #import "DTDimmingView.h" 13 | #import "DTProgressView.h" 14 | #import "DTAnimatableShapeLayer.h" 15 | 16 | #import "CATransaction+AnimateWithDuration.h" 17 | -------------------------------------------------------------------------------- /ShapesExample/Rakefile: -------------------------------------------------------------------------------- 1 | require 'xcpretty' 2 | 3 | scheme_name = "ShapeKitExample" 4 | 5 | def run(command, min_exit_status = 0) 6 | puts "Executing: `#{command}`" 7 | system(command) 8 | return $?.exitstatus 9 | end 10 | 11 | desc "Run #{scheme_name} tests" 12 | task :run_tests do 13 | $tests_success = run("xcodebuild -scheme \"#{scheme_name}\" -destination 'name=iPhone Retina (4-inch),OS=7.1' clean test | xcpretty -tc; exit ${PIPESTATUS[0]}") 14 | end 15 | 16 | task default: 'run_tests' -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 27.07.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 27.07.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | return YES; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/DimmingViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DimmingViewController.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 10.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DimmingViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/DimmingViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DimmingViewController.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 10.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "DimmingViewController.h" 10 | #import "DTDimmingView.h" 11 | 12 | @interface DimmingViewController () 13 | @property (weak, nonatomic) IBOutlet DTDimmingView *dimmingDynamicView; 14 | 15 | @end 16 | 17 | @implementation DimmingViewController 18 | 19 | -(void)viewDidLoad 20 | { 21 | [super viewDidLoad]; 22 | 23 | UIBezierPath * roundedPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(158, 251, 100, 100)]; 24 | self.dimmingDynamicView.dimmingOpacity = 0.7; 25 | self.dimmingDynamicView.visiblePath = roundedPath; 26 | [self.view addSubview:self.dimmingDynamicView]; 27 | } 28 | 29 | - (IBAction)panGestureMoved:(UIPanGestureRecognizer *)sender 30 | { 31 | CGPoint location = [sender locationInView:self.view]; 32 | 33 | self.dimmingDynamicView.visiblePath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(location.x-50, location.y-50, 34 | 100, 100)]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/DownloadButtonViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedShapesViewController.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 25.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "HighlightableShapeButton.h" 10 | 11 | @interface DownloadButtonViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/DownloadButtonViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedShapesViewController.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 25.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "DownloadButtonViewController.h" 10 | #import "DTAnimatableShapeLayer.h" 11 | #import "CATransaction+AnimateWithDuration.h" 12 | 13 | @interface DownloadButtonViewController() 14 | @property (weak, nonatomic) IBOutlet DTShapeButton *progressButton; 15 | @property (weak, nonatomic) IBOutlet HighlightableShapeButton *downloadButton; 16 | @end 17 | 18 | @implementation DownloadButtonViewController 19 | 20 | -(void)viewDidLoad 21 | { 22 | [super viewDidLoad]; 23 | 24 | self.downloadButton.shape.path = [UIBezierPath bezierPathWithRoundedRect:self.downloadButton.bounds cornerRadius:5.0f]; 25 | self.progressButton.shape.path = [UIBezierPath bezierPathWithOvalInRect:self.progressButton.bounds]; 26 | 27 | self.progressButton.shape.strokeEnd = 0.85; 28 | 29 | CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; 30 | spinAnimation.toValue = @(1*2*M_PI); 31 | spinAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 32 | spinAnimation.duration = 1.0; 33 | spinAnimation.repeatCount = INFINITY; 34 | [self.progressButton.shape.shapeLayer addAnimation:spinAnimation forKey:@"spin animation"]; 35 | } 36 | 37 | - (IBAction)downloadTapped:(id)sender 38 | { 39 | [self.downloadButton setTitle:@"" forState:UIControlStateNormal]; 40 | 41 | CGRect frame = CGRectMake(self.downloadButton.frame.origin.x - self.progressButton.frame.size.width-5, 42 | 0, 43 | self.progressButton.frame.size.width+5, 44 | self.progressButton.frame.size.height); 45 | UIBezierPath * roundedPath = [UIBezierPath bezierPathWithRoundedRect:frame 46 | cornerRadius:10.0]; 47 | [CATransaction dt_animateWithDuration:0.25 48 | animations:^{ 49 | [self.downloadButton.shape setPath:roundedPath]; 50 | } completion:^{ 51 | self.downloadButton.hidden = YES; 52 | self.progressButton.hidden = NO; 53 | }]; 54 | } 55 | 56 | - (IBAction)progressButtonTapped:(id)sender 57 | { 58 | self.downloadButton.hidden = NO; 59 | self.progressButton.hidden = YES; 60 | 61 | [CATransaction dt_animateWithDuration:0.25 62 | animations:^{ 63 | self.downloadButton.shape.path = [UIBezierPath bezierPathWithRoundedRect:self.downloadButton.bounds 64 | cornerRadius:5.0f]; 65 | } completion:^{ 66 | [self.downloadButton setTitle:@"DOWNLOAD" forState:UIControlStateNormal]; 67 | }]; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/ProgressViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressViewController.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 27.07.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ProgressViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/ProgressViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressViewController.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 27.07.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "ProgressViewController.h" 10 | #import "DTProgressView.h" 11 | 12 | @interface ProgressViewController () 13 | @property (weak, nonatomic) IBOutlet DTProgressView *simpleProgressView; 14 | @property (weak, nonatomic) IBOutlet DTProgressView *progressView; 15 | @property (weak, nonatomic) IBOutlet DTProgressView *infiniteProgressView; 16 | @property (weak, nonatomic) IBOutlet DTProgressView *ellipseProgressView; 17 | @property (weak, nonatomic) IBOutlet DTProgressView *verticalProgressView; 18 | 19 | @end 20 | 21 | @implementation ProgressViewController 22 | 23 | -(void)dealloc 24 | { 25 | [[self class] cancelPreviousPerformRequestsWithTarget:self]; 26 | } 27 | 28 | -(void)viewDidLoad 29 | { 30 | [super viewDidLoad]; 31 | 32 | [self setupSimpleProgressView]; 33 | [self setupProgressView]; 34 | [self setupInfiniteProgressView]; 35 | [self setupEllipseProgressView]; 36 | [self setupVerticalRoundedProgressView]; 37 | 38 | [self increaseProgress]; 39 | } 40 | 41 | -(void)setupSimpleProgressView 42 | { 43 | self.simpleProgressView.strokeColor = [UIColor greenColor]; 44 | } 45 | 46 | -(void)setupProgressView 47 | { 48 | self.progressView.strokeColor = [UIColor redColor]; 49 | CGFloat side = self.progressView.bounds.size.width - 5; 50 | CGRect circleRect = CGRectMake(5, 5, side-5, side-5); 51 | UIBezierPath * circlePath = [UIBezierPath bezierPathWithOvalInRect:circleRect]; 52 | self.progressView.path = circlePath; 53 | self.progressView.lineWidth = 2; 54 | } 55 | 56 | -(void)setupInfiniteProgressView 57 | { 58 | // Does not seem to work properly on iOS 8.4 and iOS 9 59 | 60 | 61 | // self.infiniteProgressView.strokeColor = [UIColor blueColor]; 62 | // 63 | // CGFloat side = self.infiniteProgressView.bounds.size.width - 5; 64 | // CGRect circleRect = CGRectMake(5, 5, side-5, side-5); 65 | // UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:circleRect]; 66 | // path.lineWidth = 1; 67 | // self.infiniteProgressView.path = path; 68 | // [self.infiniteProgressView setStrokeEnd:0.85 animated:NO]; 69 | 70 | // CABasicAnimation *spinAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 71 | // spinAnimation.fromValue = @0; 72 | // spinAnimation.toValue = @(M_PI*2); 73 | // spinAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 74 | // spinAnimation.duration = 10.0; 75 | // spinAnimation.cumulative = YES; 76 | // spinAnimation.repeatCount = INFINITY; 77 | // [self.infiniteProgressView.shapeLayer addAnimation:spinAnimation forKey:@"spin animation"]; 78 | } 79 | 80 | -(void)setupVerticalRoundedProgressView 81 | { 82 | UIBezierPath * path = [UIBezierPath bezierPath]; 83 | [path moveToPoint:CGPointMake(self.verticalProgressView.bounds.size.width/2, 0)]; 84 | [path addLineToPoint:CGPointMake(self.verticalProgressView.bounds.size.width/2, 85 | self.verticalProgressView.frame.size.height)]; 86 | 87 | path.lineWidth = 5; 88 | self.verticalProgressView.path = path; 89 | self.verticalProgressView.lineCap = kCGLineCapRound; 90 | 91 | self.verticalProgressView.strokeColor = [UIColor grayColor]; 92 | } 93 | 94 | -(void)setupEllipseProgressView 95 | { 96 | UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.ellipseProgressView.frame.size.width/2, self.ellipseProgressView.frame.size.height) 97 | radius:self.progressView.frame.size.height 98 | startAngle:M_PI 99 | endAngle:0 100 | clockwise:NO]; 101 | path.lineWidth = 2; 102 | self.ellipseProgressView.path = path; 103 | 104 | self.ellipseProgressView.strokeColor = [UIColor magentaColor]; 105 | } 106 | 107 | -(void)increaseProgress 108 | { 109 | if (self.progressView.progress == 1) 110 | { 111 | [self.progressView setProgress:0 animated:NO]; 112 | [self.simpleProgressView setProgress:0 animated:NO]; 113 | [self.ellipseProgressView setProgress:0 animated:NO]; 114 | [self.verticalProgressView setProgress:0 animated:NO]; 115 | } 116 | float random = (arc4random() % 10)/100.0; 117 | 118 | float progress = self.simpleProgressView.progress + random; 119 | 120 | [self.simpleProgressView setProgress:progress animated:YES]; 121 | [self.progressView setProgress:progress animated:YES]; 122 | [self.ellipseProgressView setProgress:progress animated:YES]; 123 | [self.verticalProgressView setProgress:progress animated:YES]; 124 | 125 | [self performSelector:@selector(increaseProgress) withObject:nil afterDelay:0.15]; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/VoiceMemosRecordButtonViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // VoiceMemosRecordButtonViewController.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 30.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DTAnimatableShapeLayer.h" 11 | 12 | @interface VoiceMemosRecordButtonViewController : UIViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/VoiceMemosRecordButtonViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // VoiceMemosRecordButtonViewController.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 30.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "VoiceMemosRecordButtonViewController.h" 10 | #import "DTShapeView.h" 11 | #import "DTShapeButton.h" 12 | #import "CATransaction+AnimateWithDuration.h" 13 | 14 | @interface VoiceMemosRecordButtonViewController () 15 | @property (weak, nonatomic) IBOutlet DTShapeView *whiteShapeView; 16 | @property (weak, nonatomic) IBOutlet DTShapeButton *recordButton; 17 | 18 | @property (nonatomic, assign) BOOL isRecording; 19 | @end 20 | 21 | @implementation VoiceMemosRecordButtonViewController 22 | 23 | - (void)viewDidLoad 24 | { 25 | [super viewDidLoad]; 26 | 27 | self.whiteShapeView.path = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(self.whiteShapeView.bounds, 4, 4)]; 28 | self.whiteShapeView.strokeColor = [UIColor whiteColor]; 29 | self.whiteShapeView.lineWidth = 4; 30 | 31 | self.recordButton.shape.path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.recordButton.frame, 8, 8) cornerRadius:(self.recordButton.frame.size.width-4)/2]; 32 | self.recordButton.shape.fillColor = [UIColor redColor]; 33 | 34 | CAShapeLayer * maskLayer = [DTAnimatableShapeLayer layer]; 35 | UIBezierPath * fromPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.recordButton.frame, 0, 0) 36 | cornerRadius:4]; 37 | maskLayer.path = [fromPath CGPath]; 38 | self.recordButton.shape.shapeLayer.mask = maskLayer; 39 | } 40 | 41 | - (IBAction)recordTapped:(id)sender 42 | { 43 | self.isRecording = !self.isRecording; 44 | 45 | UIBezierPath * fromPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.recordButton.frame, 0, 0) 46 | cornerRadius:4]; 47 | UIBezierPath * toPath = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(self.recordButton.frame, 18, 18) 48 | cornerRadius:4]; 49 | 50 | [CATransaction dt_animateWithDuration:0.25 51 | animations:^{ 52 | if (self.isRecording) 53 | { 54 | [(CAShapeLayer *)self.recordButton.shape.shapeLayer.mask setPath:[toPath CGPath]]; 55 | } 56 | else { 57 | [(CAShapeLayer *)self.recordButton.shape.shapeLayer.mask setPath:[fromPath CGPath]]; 58 | } 59 | } completion:nil]; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controllers/cat_selfie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/ShapesExample/ShapeKitExample/Controllers/cat_selfie.png -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controls/DimmableShapeButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // DimmableShapedButton.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 30.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "DTShapeButton.h" 10 | 11 | @interface DimmableShapeButton : DTShapeButton 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controls/DimmableShapeButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // DimmableShapedButton.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 30.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "DimmableShapeButton.h" 10 | 11 | @implementation DimmableShapeButton 12 | 13 | -(void)setHighlighted:(BOOL)highlighted 14 | { 15 | if (highlighted) 16 | { 17 | self.alpha = 0.3; 18 | } 19 | else { 20 | self.alpha = 1; 21 | } 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controls/HighlightableShapeButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // RoundCorneredButton.h 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 25.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "DTShapeButton.h" 10 | 11 | @interface HighlightableShapeButton : DTShapeButton 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Controls/HighlightableShapeButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // RoundCorneredButton.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 25.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import "HighlightableShapeButton.h" 10 | #import "DTShapeView.h" 11 | 12 | @implementation HighlightableShapeButton 13 | 14 | -(void)setHighlighted:(BOOL)highlighted 15 | { 16 | if (highlighted) 17 | { 18 | self.shape.fillColor = self.tintColor; 19 | self.titleLabel.textColor = [UIColor whiteColor]; 20 | } 21 | else { 22 | self.titleLabel.textColor = self.tintColor; 23 | self.shape.fillColor = [UIColor clearColor]; 24 | } 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Images.xcassets/cat_selfie.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x", 6 | "filename" : "cat_selfie.png" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | } 12 | ], 13 | "info" : { 14 | "version" : 1, 15 | "author" : "xcode" 16 | } 17 | } -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/Images.xcassets/cat_selfie.imageset/cat_selfie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MLSDev/Shapes/35d19f56082a2cde54585b14671af6f4d58ba28e/ShapesExample/ShapeKitExample/Images.xcassets/cat_selfie.imageset/cat_selfie.png -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/ShapesExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | ShapesExample 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/ShapesExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/ShapesExample.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 175 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 27.07.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExampleTests/ShapesExampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExampleTests/Specs/ShapedView/ShapedViewGettersAndSettersTestCase.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShapedViewGettersAndSettersTestCase.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 06.09.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DTShapeView.h" 11 | 12 | @interface ShapedViewGettersAndSettersTestCase : XCTestCase 13 | @property (nonatomic, strong) DTShapeView * view; 14 | 15 | @end 16 | 17 | @implementation ShapedViewGettersAndSettersTestCase 18 | 19 | - (void)setUp 20 | { 21 | [super setUp]; 22 | self.view = [DTShapeView new]; 23 | } 24 | 25 | -(void)testFillColor 26 | { 27 | [self.view setFillColor:[UIColor redColor]]; 28 | UIColor * color = [UIColor colorWithCGColor:self.view.shapeLayer.fillColor]; 29 | XCTAssert([color isEqual:[UIColor redColor]]); 30 | } 31 | 32 | -(void)testStrokeColor 33 | { 34 | [self.view setStrokeColor:[UIColor blueColor]]; 35 | UIColor * color = [UIColor colorWithCGColor:self.view.shapeLayer.strokeColor]; 36 | XCTAssert([color isEqual:[UIColor blueColor]]); 37 | } 38 | 39 | -(void)testUsesEvenOddFillRule 40 | { 41 | [self.view setUsesEvenOddFillRule:YES]; 42 | XCTAssert([self.view.shapeLayer.fillRule isEqualToString:kCAFillRuleEvenOdd]); 43 | } 44 | 45 | -(void)testFillRuleNonZero 46 | { 47 | [self.view setUsesEvenOddFillRule:NO]; 48 | XCTAssert([self.view.shapeLayer.fillRule isEqualToString:kCAFillRuleNonZero]); 49 | } 50 | 51 | -(void)testLineCap 52 | { 53 | self.view.lineCap = kCGLineCapRound; 54 | XCTAssert([self.view.shapeLayer.lineCap isEqualToString:kCALineCapRound]); 55 | 56 | self.view.lineCap = kCGLineCapButt; 57 | XCTAssert([self.view.shapeLayer.lineCap isEqualToString:kCALineCapButt]); 58 | } 59 | 60 | -(void)testLineJoin 61 | { 62 | self.view.lineJoin = kCGLineJoinBevel; 63 | XCTAssert([self.view.shapeLayer.lineJoin isEqualToString:kCALineJoinBevel]); 64 | 65 | self.view.lineJoin = kCGLineJoinMiter; 66 | XCTAssert([self.view.shapeLayer.lineJoin isEqualToString:kCALineJoinMiter]); 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExampleTests/Specs/ShapedView/ShapedViewPathTestCase.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShapedViewTestCase.m 3 | // ShapesExample 4 | // 5 | // Created by Denys Telezhkin on 03.08.14. 6 | // Copyright (c) 2014 Denys Telezhkin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DTShapeView.h" 11 | 12 | @interface ShapedViewPathTestCase : XCTestCase 13 | @property (nonatomic, strong) DTShapeView * view; 14 | 15 | @end 16 | 17 | @implementation ShapedViewPathTestCase 18 | 19 | - (void)setUp 20 | { 21 | [super setUp]; 22 | 23 | UIBezierPath * path = [UIBezierPath bezierPath]; 24 | path.lineWidth = 2; 25 | path.lineCapStyle = kCGLineCapRound; 26 | path.lineJoinStyle = kCGLineJoinRound; 27 | path.miterLimit = 6; 28 | path.usesEvenOddFillRule = YES; 29 | 30 | self.view = [DTShapeView new]; 31 | [self.view setPath:path]; 32 | } 33 | 34 | -(void)testLineWidth 35 | { 36 | XCTAssert(self.view.shapeLayer.lineWidth == 2); 37 | } 38 | 39 | -(void)testLineCapStyle 40 | { 41 | XCTAssert([self.view.shapeLayer.lineCap isEqualToString:kCALineCapRound]); 42 | } 43 | 44 | -(void)testLineJoinStyle 45 | { 46 | XCTAssert([self.view.shapeLayer.lineJoin isEqualToString:kCALineJoinRound]); 47 | } 48 | 49 | -(void)testMiterLimit 50 | { 51 | XCTAssert(self.view.shapeLayer.miterLimit == 6); 52 | } 53 | 54 | -(void)testEvenOddRule 55 | { 56 | XCTAssert([self.view.shapeLayer.fillRule isEqualToString:kCAFillRuleEvenOdd]); 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /ShapesExample/ShapeKitExampleTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ShapesExample/ShapesExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9A20D58E198E0C47005D0F7D /* ShapedViewPathTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A20D58D198E0C47005D0F7D /* ShapedViewPathTestCase.m */; }; 11 | 9A2C577319D2F4990055DD9B /* CAShapeLayer+UIBezierPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576319D2F4990055DD9B /* CAShapeLayer+UIBezierPath.m */; }; 12 | 9A2C577419D2F4990055DD9B /* CATransaction+AnimateWithDuration.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576519D2F4990055DD9B /* CATransaction+AnimateWithDuration.m */; }; 13 | 9A2C577519D2F4990055DD9B /* DTAnimatableShapeLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576719D2F4990055DD9B /* DTAnimatableShapeLayer.m */; }; 14 | 9A2C577619D2F4990055DD9B /* DTDimmingView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576919D2F4990055DD9B /* DTDimmingView.m */; }; 15 | 9A2C577719D2F4990055DD9B /* DTGraphicsConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576B19D2F4990055DD9B /* DTGraphicsConverter.m */; }; 16 | 9A2C577819D2F4990055DD9B /* DTProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576D19D2F4990055DD9B /* DTProgressView.m */; }; 17 | 9A2C577919D2F4990055DD9B /* DTShapeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C576F19D2F4990055DD9B /* DTShapeButton.m */; }; 18 | 9A2C577A19D2F4990055DD9B /* DTShapeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A2C577119D2F4990055DD9B /* DTShapeView.m */; }; 19 | 9A5DF42719854B200034FF62 /* ShapesExample.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9A5DF42619854B200034FF62 /* ShapesExample.storyboard */; }; 20 | 9A5DF42A198562C80034FF62 /* ProgressViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A5DF429198562C80034FF62 /* ProgressViewController.m */; }; 21 | 9A79790D19974D1700E43B41 /* DimmingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A79790C19974D1700E43B41 /* DimmingViewController.m */; }; 22 | 9AA0172A19851133001A0666 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA0172919851133001A0666 /* Foundation.framework */; }; 23 | 9AA0172C19851133001A0666 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA0172B19851133001A0666 /* CoreGraphics.framework */; }; 24 | 9AA0172E19851133001A0666 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA0172D19851133001A0666 /* UIKit.framework */; }; 25 | 9AA0173419851133001A0666 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9AA0173219851133001A0666 /* InfoPlist.strings */; }; 26 | 9AA0173619851133001A0666 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AA0173519851133001A0666 /* main.m */; }; 27 | 9AA0173A19851133001A0666 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AA0173919851133001A0666 /* AppDelegate.m */; }; 28 | 9AA0173C19851133001A0666 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9AA0173B19851133001A0666 /* Images.xcassets */; }; 29 | 9AA0174319851133001A0666 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA0174219851133001A0666 /* XCTest.framework */; }; 30 | 9AA0174419851133001A0666 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA0172919851133001A0666 /* Foundation.framework */; }; 31 | 9AA0174519851133001A0666 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9AA0172D19851133001A0666 /* UIKit.framework */; }; 32 | 9AA0174D19851133001A0666 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9AA0174B19851133001A0666 /* InfoPlist.strings */; }; 33 | 9AA0296519B1F9FC0097AAE2 /* DimmableShapeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AA0296419B1F9FC0097AAE2 /* DimmableShapeButton.m */; }; 34 | 9AA0296819B200B40097AAE2 /* VoiceMemosRecordButtonViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AA0296719B200B40097AAE2 /* VoiceMemosRecordButtonViewController.m */; }; 35 | 9AAA136919BB07A90073354A /* ShapedViewGettersAndSettersTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AAA136819BB07A90073354A /* ShapedViewGettersAndSettersTestCase.m */; }; 36 | 9AD1E75919ABA84800576928 /* DownloadButtonViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD1E75819ABA84800576928 /* DownloadButtonViewController.m */; }; 37 | 9AD1E76119ABAD8000576928 /* HighlightableShapeButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 9AD1E76019ABAD8000576928 /* HighlightableShapeButton.m */; }; 38 | /* End PBXBuildFile section */ 39 | 40 | /* Begin PBXContainerItemProxy section */ 41 | 9A216E8119D2F59600FF10F5 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = 9AA0171E19851133001A0666 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = 9AA0172519851133001A0666; 46 | remoteInfo = ShapesExample; 47 | }; 48 | 9AA0174619851133001A0666 /* PBXContainerItemProxy */ = { 49 | isa = PBXContainerItemProxy; 50 | containerPortal = 9AA0171E19851133001A0666 /* Project object */; 51 | proxyType = 1; 52 | remoteGlobalIDString = 9AA0172519851133001A0666; 53 | remoteInfo = ShapeKitExample; 54 | }; 55 | /* End PBXContainerItemProxy section */ 56 | 57 | /* Begin PBXFileReference section */ 58 | 9A20D58D198E0C47005D0F7D /* ShapedViewPathTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShapedViewPathTestCase.m; path = Specs/ShapedView/ShapedViewPathTestCase.m; sourceTree = ""; }; 59 | 9A2C576219D2F4990055DD9B /* CAShapeLayer+UIBezierPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CAShapeLayer+UIBezierPath.h"; sourceTree = ""; }; 60 | 9A2C576319D2F4990055DD9B /* CAShapeLayer+UIBezierPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CAShapeLayer+UIBezierPath.m"; sourceTree = ""; }; 61 | 9A2C576419D2F4990055DD9B /* CATransaction+AnimateWithDuration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CATransaction+AnimateWithDuration.h"; sourceTree = ""; }; 62 | 9A2C576519D2F4990055DD9B /* CATransaction+AnimateWithDuration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CATransaction+AnimateWithDuration.m"; sourceTree = ""; }; 63 | 9A2C576619D2F4990055DD9B /* DTAnimatableShapeLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTAnimatableShapeLayer.h; sourceTree = ""; }; 64 | 9A2C576719D2F4990055DD9B /* DTAnimatableShapeLayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTAnimatableShapeLayer.m; sourceTree = ""; }; 65 | 9A2C576819D2F4990055DD9B /* DTDimmingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTDimmingView.h; sourceTree = ""; }; 66 | 9A2C576919D2F4990055DD9B /* DTDimmingView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTDimmingView.m; sourceTree = ""; }; 67 | 9A2C576A19D2F4990055DD9B /* DTGraphicsConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTGraphicsConverter.h; sourceTree = ""; }; 68 | 9A2C576B19D2F4990055DD9B /* DTGraphicsConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTGraphicsConverter.m; sourceTree = ""; }; 69 | 9A2C576C19D2F4990055DD9B /* DTProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTProgressView.h; sourceTree = ""; }; 70 | 9A2C576D19D2F4990055DD9B /* DTProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTProgressView.m; sourceTree = ""; }; 71 | 9A2C576E19D2F4990055DD9B /* DTShapeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTShapeButton.h; sourceTree = ""; }; 72 | 9A2C576F19D2F4990055DD9B /* DTShapeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTShapeButton.m; sourceTree = ""; }; 73 | 9A2C577019D2F4990055DD9B /* DTShapeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DTShapeView.h; sourceTree = ""; }; 74 | 9A2C577119D2F4990055DD9B /* DTShapeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DTShapeView.m; sourceTree = ""; }; 75 | 9A2C577219D2F4990055DD9B /* Shapes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shapes.h; sourceTree = ""; }; 76 | 9A5DF42619854B200034FF62 /* ShapesExample.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ShapesExample.storyboard; sourceTree = ""; }; 77 | 9A5DF428198562C80034FF62 /* ProgressViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressViewController.h; path = Controllers/ProgressViewController.h; sourceTree = ""; }; 78 | 9A5DF429198562C80034FF62 /* ProgressViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressViewController.m; path = Controllers/ProgressViewController.m; sourceTree = ""; }; 79 | 9A79790B19974D1700E43B41 /* DimmingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DimmingViewController.h; path = Controllers/DimmingViewController.h; sourceTree = ""; }; 80 | 9A79790C19974D1700E43B41 /* DimmingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DimmingViewController.m; path = Controllers/DimmingViewController.m; sourceTree = ""; }; 81 | 9AA0172619851133001A0666 /* ShapesExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ShapesExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 9AA0172919851133001A0666 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 83 | 9AA0172B19851133001A0666 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 84 | 9AA0172D19851133001A0666 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 85 | 9AA0173119851133001A0666 /* ShapesExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ShapesExample-Info.plist"; sourceTree = ""; }; 86 | 9AA0173319851133001A0666 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 87 | 9AA0173519851133001A0666 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 88 | 9AA0173719851133001A0666 /* ShapesExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ShapesExample-Prefix.pch"; sourceTree = ""; }; 89 | 9AA0173819851133001A0666 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 90 | 9AA0173919851133001A0666 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 91 | 9AA0173B19851133001A0666 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 92 | 9AA0174119851133001A0666 /* ShapesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ShapesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 93 | 9AA0174219851133001A0666 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 94 | 9AA0174A19851133001A0666 /* ShapesExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ShapesExampleTests-Info.plist"; sourceTree = ""; }; 95 | 9AA0174C19851133001A0666 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 96 | 9AA0296319B1F9FC0097AAE2 /* DimmableShapeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DimmableShapeButton.h; path = Controls/DimmableShapeButton.h; sourceTree = ""; }; 97 | 9AA0296419B1F9FC0097AAE2 /* DimmableShapeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DimmableShapeButton.m; path = Controls/DimmableShapeButton.m; sourceTree = ""; }; 98 | 9AA0296619B200B40097AAE2 /* VoiceMemosRecordButtonViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VoiceMemosRecordButtonViewController.h; path = Controllers/VoiceMemosRecordButtonViewController.h; sourceTree = ""; }; 99 | 9AA0296719B200B40097AAE2 /* VoiceMemosRecordButtonViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VoiceMemosRecordButtonViewController.m; path = Controllers/VoiceMemosRecordButtonViewController.m; sourceTree = ""; }; 100 | 9AAA136819BB07A90073354A /* ShapedViewGettersAndSettersTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ShapedViewGettersAndSettersTestCase.m; path = Specs/ShapedView/ShapedViewGettersAndSettersTestCase.m; sourceTree = ""; }; 101 | 9AD1E75719ABA84800576928 /* DownloadButtonViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DownloadButtonViewController.h; path = Controllers/DownloadButtonViewController.h; sourceTree = ""; }; 102 | 9AD1E75819ABA84800576928 /* DownloadButtonViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DownloadButtonViewController.m; path = Controllers/DownloadButtonViewController.m; sourceTree = ""; }; 103 | 9AD1E75F19ABAD8000576928 /* HighlightableShapeButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HighlightableShapeButton.h; path = Controls/HighlightableShapeButton.h; sourceTree = ""; }; 104 | 9AD1E76019ABAD8000576928 /* HighlightableShapeButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HighlightableShapeButton.m; path = Controls/HighlightableShapeButton.m; sourceTree = ""; }; 105 | /* End PBXFileReference section */ 106 | 107 | /* Begin PBXFrameworksBuildPhase section */ 108 | 9AA0172319851133001A0666 /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | 9AA0172C19851133001A0666 /* CoreGraphics.framework in Frameworks */, 113 | 9AA0172E19851133001A0666 /* UIKit.framework in Frameworks */, 114 | 9AA0172A19851133001A0666 /* Foundation.framework in Frameworks */, 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | 9AA0173E19851133001A0666 /* Frameworks */ = { 119 | isa = PBXFrameworksBuildPhase; 120 | buildActionMask = 2147483647; 121 | files = ( 122 | 9AA0174319851133001A0666 /* XCTest.framework in Frameworks */, 123 | 9AA0174519851133001A0666 /* UIKit.framework in Frameworks */, 124 | 9AA0174419851133001A0666 /* Foundation.framework in Frameworks */, 125 | ); 126 | runOnlyForDeploymentPostprocessing = 0; 127 | }; 128 | /* End PBXFrameworksBuildPhase section */ 129 | 130 | /* Begin PBXGroup section */ 131 | 9A20D58C198E0C24005D0F7D /* Specs */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 9A20D58D198E0C47005D0F7D /* ShapedViewPathTestCase.m */, 135 | 9AAA136819BB07A90073354A /* ShapedViewGettersAndSettersTestCase.m */, 136 | ); 137 | name = Specs; 138 | sourceTree = ""; 139 | }; 140 | 9A2C576119D2F4990055DD9B /* Shapes */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 9A2C576219D2F4990055DD9B /* CAShapeLayer+UIBezierPath.h */, 144 | 9A2C576319D2F4990055DD9B /* CAShapeLayer+UIBezierPath.m */, 145 | 9A2C576419D2F4990055DD9B /* CATransaction+AnimateWithDuration.h */, 146 | 9A2C576519D2F4990055DD9B /* CATransaction+AnimateWithDuration.m */, 147 | 9A2C576619D2F4990055DD9B /* DTAnimatableShapeLayer.h */, 148 | 9A2C576719D2F4990055DD9B /* DTAnimatableShapeLayer.m */, 149 | 9A2C576819D2F4990055DD9B /* DTDimmingView.h */, 150 | 9A2C576919D2F4990055DD9B /* DTDimmingView.m */, 151 | 9A2C576A19D2F4990055DD9B /* DTGraphicsConverter.h */, 152 | 9A2C576B19D2F4990055DD9B /* DTGraphicsConverter.m */, 153 | 9A2C576C19D2F4990055DD9B /* DTProgressView.h */, 154 | 9A2C576D19D2F4990055DD9B /* DTProgressView.m */, 155 | 9A2C576E19D2F4990055DD9B /* DTShapeButton.h */, 156 | 9A2C576F19D2F4990055DD9B /* DTShapeButton.m */, 157 | 9A2C577019D2F4990055DD9B /* DTShapeView.h */, 158 | 9A2C577119D2F4990055DD9B /* DTShapeView.m */, 159 | 9A2C577219D2F4990055DD9B /* Shapes.h */, 160 | ); 161 | name = Shapes; 162 | path = ../Shapes; 163 | sourceTree = ""; 164 | }; 165 | 9A5DF42B198562CD0034FF62 /* Progress */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 9A5DF428198562C80034FF62 /* ProgressViewController.h */, 169 | 9A5DF429198562C80034FF62 /* ProgressViewController.m */, 170 | ); 171 | name = Progress; 172 | sourceTree = ""; 173 | }; 174 | 9A79790A19974C7D00E43B41 /* Dimming */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 9A79790B19974D1700E43B41 /* DimmingViewController.h */, 178 | 9A79790C19974D1700E43B41 /* DimmingViewController.m */, 179 | ); 180 | name = Dimming; 181 | sourceTree = ""; 182 | }; 183 | 9AA0171D19851133001A0666 = { 184 | isa = PBXGroup; 185 | children = ( 186 | 9A2C576119D2F4990055DD9B /* Shapes */, 187 | 9AA0172F19851133001A0666 /* ShapesExample */, 188 | 9AA0174819851133001A0666 /* ShapesTests */, 189 | 9AA0172819851133001A0666 /* Frameworks */, 190 | 9AA0172719851133001A0666 /* Products */, 191 | ); 192 | sourceTree = ""; 193 | }; 194 | 9AA0172719851133001A0666 /* Products */ = { 195 | isa = PBXGroup; 196 | children = ( 197 | 9AA0172619851133001A0666 /* ShapesExample.app */, 198 | 9AA0174119851133001A0666 /* ShapesTests.xctest */, 199 | ); 200 | name = Products; 201 | sourceTree = ""; 202 | }; 203 | 9AA0172819851133001A0666 /* Frameworks */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | 9AA0172919851133001A0666 /* Foundation.framework */, 207 | 9AA0172B19851133001A0666 /* CoreGraphics.framework */, 208 | 9AA0172D19851133001A0666 /* UIKit.framework */, 209 | 9AA0174219851133001A0666 /* XCTest.framework */, 210 | ); 211 | name = Frameworks; 212 | sourceTree = ""; 213 | }; 214 | 9AA0172F19851133001A0666 /* ShapesExample */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 9AA0173819851133001A0666 /* AppDelegate.h */, 218 | 9AA0173919851133001A0666 /* AppDelegate.m */, 219 | 9A5DF42619854B200034FF62 /* ShapesExample.storyboard */, 220 | 9A79790A19974C7D00E43B41 /* Dimming */, 221 | 9A5DF42B198562CD0034FF62 /* Progress */, 222 | 9AD1E75619ABA82900576928 /* Animated buttons */, 223 | 9AA0173B19851133001A0666 /* Images.xcassets */, 224 | 9AA0173019851133001A0666 /* Supporting Files */, 225 | ); 226 | name = ShapesExample; 227 | path = ShapeKitExample; 228 | sourceTree = ""; 229 | }; 230 | 9AA0173019851133001A0666 /* Supporting Files */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | 9AA0173119851133001A0666 /* ShapesExample-Info.plist */, 234 | 9AA0173219851133001A0666 /* InfoPlist.strings */, 235 | 9AA0173519851133001A0666 /* main.m */, 236 | 9AA0173719851133001A0666 /* ShapesExample-Prefix.pch */, 237 | ); 238 | name = "Supporting Files"; 239 | sourceTree = ""; 240 | }; 241 | 9AA0174819851133001A0666 /* ShapesTests */ = { 242 | isa = PBXGroup; 243 | children = ( 244 | 9A20D58C198E0C24005D0F7D /* Specs */, 245 | 9AA0174919851133001A0666 /* Supporting Files */, 246 | ); 247 | name = ShapesTests; 248 | path = ShapeKitExampleTests; 249 | sourceTree = ""; 250 | }; 251 | 9AA0174919851133001A0666 /* Supporting Files */ = { 252 | isa = PBXGroup; 253 | children = ( 254 | 9AA0174A19851133001A0666 /* ShapesExampleTests-Info.plist */, 255 | 9AA0174B19851133001A0666 /* InfoPlist.strings */, 256 | ); 257 | name = "Supporting Files"; 258 | sourceTree = ""; 259 | }; 260 | 9AD1E75619ABA82900576928 /* Animated buttons */ = { 261 | isa = PBXGroup; 262 | children = ( 263 | 9AD1E75E19ABAD3B00576928 /* Buttons */, 264 | 9AD1E75719ABA84800576928 /* DownloadButtonViewController.h */, 265 | 9AD1E75819ABA84800576928 /* DownloadButtonViewController.m */, 266 | 9AA0296619B200B40097AAE2 /* VoiceMemosRecordButtonViewController.h */, 267 | 9AA0296719B200B40097AAE2 /* VoiceMemosRecordButtonViewController.m */, 268 | ); 269 | name = "Animated buttons"; 270 | sourceTree = ""; 271 | }; 272 | 9AD1E75E19ABAD3B00576928 /* Buttons */ = { 273 | isa = PBXGroup; 274 | children = ( 275 | 9AD1E75F19ABAD8000576928 /* HighlightableShapeButton.h */, 276 | 9AD1E76019ABAD8000576928 /* HighlightableShapeButton.m */, 277 | 9AA0296319B1F9FC0097AAE2 /* DimmableShapeButton.h */, 278 | 9AA0296419B1F9FC0097AAE2 /* DimmableShapeButton.m */, 279 | ); 280 | name = Buttons; 281 | sourceTree = ""; 282 | }; 283 | /* End PBXGroup section */ 284 | 285 | /* Begin PBXNativeTarget section */ 286 | 9AA0172519851133001A0666 /* ShapesExample */ = { 287 | isa = PBXNativeTarget; 288 | buildConfigurationList = 9AA0175219851133001A0666 /* Build configuration list for PBXNativeTarget "ShapesExample" */; 289 | buildPhases = ( 290 | 9AA0172219851133001A0666 /* Sources */, 291 | 9AA0172319851133001A0666 /* Frameworks */, 292 | 9AA0172419851133001A0666 /* Resources */, 293 | ); 294 | buildRules = ( 295 | ); 296 | dependencies = ( 297 | ); 298 | name = ShapesExample; 299 | productName = ShapeKitExample; 300 | productReference = 9AA0172619851133001A0666 /* ShapesExample.app */; 301 | productType = "com.apple.product-type.application"; 302 | }; 303 | 9AA0174019851133001A0666 /* ShapesTests */ = { 304 | isa = PBXNativeTarget; 305 | buildConfigurationList = 9AA0175519851133001A0666 /* Build configuration list for PBXNativeTarget "ShapesTests" */; 306 | buildPhases = ( 307 | 9AA0173D19851133001A0666 /* Sources */, 308 | 9AA0173E19851133001A0666 /* Frameworks */, 309 | 9AA0173F19851133001A0666 /* Resources */, 310 | ); 311 | buildRules = ( 312 | ); 313 | dependencies = ( 314 | 9AA0174719851133001A0666 /* PBXTargetDependency */, 315 | 9A216E8219D2F59600FF10F5 /* PBXTargetDependency */, 316 | ); 317 | name = ShapesTests; 318 | productName = ShapeKitExampleTests; 319 | productReference = 9AA0174119851133001A0666 /* ShapesTests.xctest */; 320 | productType = "com.apple.product-type.bundle.unit-test"; 321 | }; 322 | /* End PBXNativeTarget section */ 323 | 324 | /* Begin PBXProject section */ 325 | 9AA0171E19851133001A0666 /* Project object */ = { 326 | isa = PBXProject; 327 | attributes = { 328 | LastUpgradeCheck = 0700; 329 | ORGANIZATIONNAME = "Denys Telezhkin"; 330 | TargetAttributes = { 331 | 9AA0174019851133001A0666 = { 332 | TestTargetID = 9AA0172519851133001A0666; 333 | }; 334 | }; 335 | }; 336 | buildConfigurationList = 9AA0172119851133001A0666 /* Build configuration list for PBXProject "ShapesExample" */; 337 | compatibilityVersion = "Xcode 3.2"; 338 | developmentRegion = English; 339 | hasScannedForEncodings = 0; 340 | knownRegions = ( 341 | en, 342 | ); 343 | mainGroup = 9AA0171D19851133001A0666; 344 | productRefGroup = 9AA0172719851133001A0666 /* Products */; 345 | projectDirPath = ""; 346 | projectRoot = ""; 347 | targets = ( 348 | 9AA0172519851133001A0666 /* ShapesExample */, 349 | 9AA0174019851133001A0666 /* ShapesTests */, 350 | ); 351 | }; 352 | /* End PBXProject section */ 353 | 354 | /* Begin PBXResourcesBuildPhase section */ 355 | 9AA0172419851133001A0666 /* Resources */ = { 356 | isa = PBXResourcesBuildPhase; 357 | buildActionMask = 2147483647; 358 | files = ( 359 | 9A5DF42719854B200034FF62 /* ShapesExample.storyboard in Resources */, 360 | 9AA0173419851133001A0666 /* InfoPlist.strings in Resources */, 361 | 9AA0173C19851133001A0666 /* Images.xcassets in Resources */, 362 | ); 363 | runOnlyForDeploymentPostprocessing = 0; 364 | }; 365 | 9AA0173F19851133001A0666 /* Resources */ = { 366 | isa = PBXResourcesBuildPhase; 367 | buildActionMask = 2147483647; 368 | files = ( 369 | 9AA0174D19851133001A0666 /* InfoPlist.strings in Resources */, 370 | ); 371 | runOnlyForDeploymentPostprocessing = 0; 372 | }; 373 | /* End PBXResourcesBuildPhase section */ 374 | 375 | /* Begin PBXSourcesBuildPhase section */ 376 | 9AA0172219851133001A0666 /* Sources */ = { 377 | isa = PBXSourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | 9A2C577919D2F4990055DD9B /* DTShapeButton.m in Sources */, 381 | 9A2C577519D2F4990055DD9B /* DTAnimatableShapeLayer.m in Sources */, 382 | 9A5DF42A198562C80034FF62 /* ProgressViewController.m in Sources */, 383 | 9A2C577719D2F4990055DD9B /* DTGraphicsConverter.m in Sources */, 384 | 9A2C577619D2F4990055DD9B /* DTDimmingView.m in Sources */, 385 | 9AA0296519B1F9FC0097AAE2 /* DimmableShapeButton.m in Sources */, 386 | 9A2C577319D2F4990055DD9B /* CAShapeLayer+UIBezierPath.m in Sources */, 387 | 9AD1E75919ABA84800576928 /* DownloadButtonViewController.m in Sources */, 388 | 9A2C577419D2F4990055DD9B /* CATransaction+AnimateWithDuration.m in Sources */, 389 | 9AA0173A19851133001A0666 /* AppDelegate.m in Sources */, 390 | 9AD1E76119ABAD8000576928 /* HighlightableShapeButton.m in Sources */, 391 | 9AA0296819B200B40097AAE2 /* VoiceMemosRecordButtonViewController.m in Sources */, 392 | 9A2C577A19D2F4990055DD9B /* DTShapeView.m in Sources */, 393 | 9A2C577819D2F4990055DD9B /* DTProgressView.m in Sources */, 394 | 9A79790D19974D1700E43B41 /* DimmingViewController.m in Sources */, 395 | 9AA0173619851133001A0666 /* main.m in Sources */, 396 | ); 397 | runOnlyForDeploymentPostprocessing = 0; 398 | }; 399 | 9AA0173D19851133001A0666 /* Sources */ = { 400 | isa = PBXSourcesBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | 9A20D58E198E0C47005D0F7D /* ShapedViewPathTestCase.m in Sources */, 404 | 9AAA136919BB07A90073354A /* ShapedViewGettersAndSettersTestCase.m in Sources */, 405 | ); 406 | runOnlyForDeploymentPostprocessing = 0; 407 | }; 408 | /* End PBXSourcesBuildPhase section */ 409 | 410 | /* Begin PBXTargetDependency section */ 411 | 9A216E8219D2F59600FF10F5 /* PBXTargetDependency */ = { 412 | isa = PBXTargetDependency; 413 | target = 9AA0172519851133001A0666 /* ShapesExample */; 414 | targetProxy = 9A216E8119D2F59600FF10F5 /* PBXContainerItemProxy */; 415 | }; 416 | 9AA0174719851133001A0666 /* PBXTargetDependency */ = { 417 | isa = PBXTargetDependency; 418 | target = 9AA0172519851133001A0666 /* ShapesExample */; 419 | targetProxy = 9AA0174619851133001A0666 /* PBXContainerItemProxy */; 420 | }; 421 | /* End PBXTargetDependency section */ 422 | 423 | /* Begin PBXVariantGroup section */ 424 | 9AA0173219851133001A0666 /* InfoPlist.strings */ = { 425 | isa = PBXVariantGroup; 426 | children = ( 427 | 9AA0173319851133001A0666 /* en */, 428 | ); 429 | name = InfoPlist.strings; 430 | sourceTree = ""; 431 | }; 432 | 9AA0174B19851133001A0666 /* InfoPlist.strings */ = { 433 | isa = PBXVariantGroup; 434 | children = ( 435 | 9AA0174C19851133001A0666 /* en */, 436 | ); 437 | name = InfoPlist.strings; 438 | sourceTree = ""; 439 | }; 440 | /* End PBXVariantGroup section */ 441 | 442 | /* Begin XCBuildConfiguration section */ 443 | 9AA0175019851133001A0666 /* Debug */ = { 444 | isa = XCBuildConfiguration; 445 | buildSettings = { 446 | ALWAYS_SEARCH_USER_PATHS = NO; 447 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 448 | CLANG_CXX_LIBRARY = "libc++"; 449 | CLANG_ENABLE_MODULES = YES; 450 | CLANG_ENABLE_OBJC_ARC = YES; 451 | CLANG_WARN_BOOL_CONVERSION = YES; 452 | CLANG_WARN_CONSTANT_CONVERSION = YES; 453 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 454 | CLANG_WARN_EMPTY_BODY = YES; 455 | CLANG_WARN_ENUM_CONVERSION = YES; 456 | CLANG_WARN_INT_CONVERSION = YES; 457 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 458 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 459 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 460 | COPY_PHASE_STRIP = NO; 461 | ENABLE_TESTABILITY = YES; 462 | GCC_C_LANGUAGE_STANDARD = gnu99; 463 | GCC_DYNAMIC_NO_PIC = NO; 464 | GCC_OPTIMIZATION_LEVEL = 0; 465 | GCC_PREPROCESSOR_DEFINITIONS = ( 466 | "DEBUG=1", 467 | "$(inherited)", 468 | ); 469 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 470 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 471 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 472 | GCC_WARN_UNDECLARED_SELECTOR = YES; 473 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 474 | GCC_WARN_UNUSED_FUNCTION = YES; 475 | GCC_WARN_UNUSED_VARIABLE = YES; 476 | IPHONEOS_DEPLOYMENT_TARGET = 8; 477 | ONLY_ACTIVE_ARCH = YES; 478 | SDKROOT = iphoneos; 479 | TARGETED_DEVICE_FAMILY = "1,2"; 480 | }; 481 | name = Debug; 482 | }; 483 | 9AA0175119851133001A0666 /* Release */ = { 484 | isa = XCBuildConfiguration; 485 | buildSettings = { 486 | ALWAYS_SEARCH_USER_PATHS = NO; 487 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 488 | CLANG_CXX_LIBRARY = "libc++"; 489 | CLANG_ENABLE_MODULES = YES; 490 | CLANG_ENABLE_OBJC_ARC = YES; 491 | CLANG_WARN_BOOL_CONVERSION = YES; 492 | CLANG_WARN_CONSTANT_CONVERSION = YES; 493 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 494 | CLANG_WARN_EMPTY_BODY = YES; 495 | CLANG_WARN_ENUM_CONVERSION = YES; 496 | CLANG_WARN_INT_CONVERSION = YES; 497 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 498 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 499 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 500 | COPY_PHASE_STRIP = YES; 501 | ENABLE_NS_ASSERTIONS = NO; 502 | GCC_C_LANGUAGE_STANDARD = gnu99; 503 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 504 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 505 | GCC_WARN_UNDECLARED_SELECTOR = YES; 506 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 507 | GCC_WARN_UNUSED_FUNCTION = YES; 508 | GCC_WARN_UNUSED_VARIABLE = YES; 509 | IPHONEOS_DEPLOYMENT_TARGET = 8; 510 | SDKROOT = iphoneos; 511 | TARGETED_DEVICE_FAMILY = "1,2"; 512 | VALIDATE_PRODUCT = YES; 513 | }; 514 | name = Release; 515 | }; 516 | 9AA0175319851133001A0666 /* Debug */ = { 517 | isa = XCBuildConfiguration; 518 | buildSettings = { 519 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 520 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 521 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 522 | GCC_PREFIX_HEADER = "ShapeKitExample/ShapesExample-Prefix.pch"; 523 | INFOPLIST_FILE = "ShapeKitExample/ShapesExample-Info.plist"; 524 | IPHONEOS_DEPLOYMENT_TARGET = 8; 525 | PRODUCT_BUNDLE_IDENTIFIER = "com.mlsdev.${PRODUCT_NAME:rfc1034identifier}"; 526 | PRODUCT_NAME = "$(TARGET_NAME)"; 527 | TARGETED_DEVICE_FAMILY = 1; 528 | WRAPPER_EXTENSION = app; 529 | }; 530 | name = Debug; 531 | }; 532 | 9AA0175419851133001A0666 /* Release */ = { 533 | isa = XCBuildConfiguration; 534 | buildSettings = { 535 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 536 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 537 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 538 | GCC_PREFIX_HEADER = "ShapeKitExample/ShapesExample-Prefix.pch"; 539 | INFOPLIST_FILE = "ShapeKitExample/ShapesExample-Info.plist"; 540 | IPHONEOS_DEPLOYMENT_TARGET = 8; 541 | PRODUCT_BUNDLE_IDENTIFIER = "com.mlsdev.${PRODUCT_NAME:rfc1034identifier}"; 542 | PRODUCT_NAME = "$(TARGET_NAME)"; 543 | TARGETED_DEVICE_FAMILY = 1; 544 | WRAPPER_EXTENSION = app; 545 | }; 546 | name = Release; 547 | }; 548 | 9AA0175619851133001A0666 /* Debug */ = { 549 | isa = XCBuildConfiguration; 550 | buildSettings = { 551 | BUNDLE_LOADER = "$(TEST_HOST)"; 552 | FRAMEWORK_SEARCH_PATHS = ( 553 | "$(SDKROOT)/Developer/Library/Frameworks", 554 | "$(inherited)", 555 | "$(DEVELOPER_FRAMEWORKS_DIR)", 556 | ); 557 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 558 | GCC_PREFIX_HEADER = "ShapeKitExample/ShapesExample-Prefix.pch"; 559 | GCC_PREPROCESSOR_DEFINITIONS = ( 560 | "DEBUG=1", 561 | "$(inherited)", 562 | ); 563 | INFOPLIST_FILE = "ShapeKitExampleTests/ShapesExampleTests-Info.plist"; 564 | PRODUCT_BUNDLE_IDENTIFIER = "com.mlsdev.${PRODUCT_NAME:rfc1034identifier}"; 565 | PRODUCT_NAME = "$(TARGET_NAME)"; 566 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ShapesExample.app/ShapesExample"; 567 | WRAPPER_EXTENSION = xctest; 568 | }; 569 | name = Debug; 570 | }; 571 | 9AA0175719851133001A0666 /* Release */ = { 572 | isa = XCBuildConfiguration; 573 | buildSettings = { 574 | BUNDLE_LOADER = "$(TEST_HOST)"; 575 | FRAMEWORK_SEARCH_PATHS = ( 576 | "$(SDKROOT)/Developer/Library/Frameworks", 577 | "$(inherited)", 578 | "$(DEVELOPER_FRAMEWORKS_DIR)", 579 | ); 580 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 581 | GCC_PREFIX_HEADER = "ShapeKitExample/ShapesExample-Prefix.pch"; 582 | INFOPLIST_FILE = "ShapeKitExampleTests/ShapesExampleTests-Info.plist"; 583 | PRODUCT_BUNDLE_IDENTIFIER = "com.mlsdev.${PRODUCT_NAME:rfc1034identifier}"; 584 | PRODUCT_NAME = "$(TARGET_NAME)"; 585 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ShapesExample.app/ShapesExample"; 586 | WRAPPER_EXTENSION = xctest; 587 | }; 588 | name = Release; 589 | }; 590 | /* End XCBuildConfiguration section */ 591 | 592 | /* Begin XCConfigurationList section */ 593 | 9AA0172119851133001A0666 /* Build configuration list for PBXProject "ShapesExample" */ = { 594 | isa = XCConfigurationList; 595 | buildConfigurations = ( 596 | 9AA0175019851133001A0666 /* Debug */, 597 | 9AA0175119851133001A0666 /* Release */, 598 | ); 599 | defaultConfigurationIsVisible = 0; 600 | defaultConfigurationName = Release; 601 | }; 602 | 9AA0175219851133001A0666 /* Build configuration list for PBXNativeTarget "ShapesExample" */ = { 603 | isa = XCConfigurationList; 604 | buildConfigurations = ( 605 | 9AA0175319851133001A0666 /* Debug */, 606 | 9AA0175419851133001A0666 /* Release */, 607 | ); 608 | defaultConfigurationIsVisible = 0; 609 | defaultConfigurationName = Release; 610 | }; 611 | 9AA0175519851133001A0666 /* Build configuration list for PBXNativeTarget "ShapesTests" */ = { 612 | isa = XCConfigurationList; 613 | buildConfigurations = ( 614 | 9AA0175619851133001A0666 /* Debug */, 615 | 9AA0175719851133001A0666 /* Release */, 616 | ); 617 | defaultConfigurationIsVisible = 0; 618 | defaultConfigurationName = Release; 619 | }; 620 | /* End XCConfigurationList section */ 621 | }; 622 | rootObject = 9AA0171E19851133001A0666 /* Project object */; 623 | } 624 | -------------------------------------------------------------------------------- /ShapesExample/ShapesExample.xcodeproj/xcshareddata/xcschemes/ShapesExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ShapesExample/ShapesExample.xcodeproj/xcshareddata/xcschemes/ShapesTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | --------------------------------------------------------------------------------