├── .gitignore ├── .travis.yml ├── Example ├── Podfile ├── SmoothLineView.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── SmoothLineView-Example.xcscheme ├── SmoothLineView.xcworkspace │ └── contents.xcworkspacedata ├── SmoothLineView │ ├── Base.lproj │ │ └── Main_iPhone.storyboard │ ├── ENDAppDelegate.h │ ├── ENDAppDelegate.m │ ├── ENDViewController.h │ ├── ENDViewController.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── SmoothLineView-Info.plist │ ├── SmoothLineView-Prefix.pch │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m └── Tests │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ ├── Tests.m │ └── en.lproj │ └── InfoPlist.strings ├── Info.plist ├── LICENSE ├── Pod ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── ENDBrush.h │ ├── ENDBrush.m │ ├── ENDBrushShadow.h │ ├── ENDBrushShadow.m │ ├── ENDDrawFillWithColorOperation.h │ ├── ENDDrawFillWithColorOperation.m │ ├── ENDDrawGestureRecognizer.h │ ├── ENDDrawGestureRecognizer.m │ ├── ENDDrawOperation.h │ ├── ENDDrawPathOperation.h │ ├── ENDDrawPathOperation.m │ ├── ENDDrawSession.h │ ├── ENDDrawSession.m │ ├── LVSmoothLineView.h │ ├── LVSmoothLineView.m │ └── SmoothLineView.h ├── README.md ├── SmoothLineView.podspec ├── SmoothLineView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── SmoothLineView.xcscheme └── SmoothLineViewTests ├── ENDDrawPathOperationTests.m ├── Info.plist └── LVSmoothLineViewTests.m /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | Pods/ 22 | Podfile.lock 23 | 24 | # Bundler 25 | .bundle 26 | 27 | Artifacts/ 28 | 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 32 | # 33 | # Note: if you ignore the Pods directory, make sure to uncomment 34 | # `pod install` in .travis.yml 35 | # 36 | # Pods/ 37 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | language: objective-c 6 | # cache: cocoapods 7 | # podfile: Example/Podfile 8 | # before_install: 9 | # - gem install cocoapods # Since Travis is not always on latest version 10 | # - pod install --project-directory=Example 11 | install: 12 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 13 | script: 14 | - set -o pipefail && xcodebuild test -workspace Example/SmoothLineView.xcworkspace -scheme SmoothLineView-Example -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty -c 15 | - pod lib lint --quick 16 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | use_frameworks! 3 | 4 | target 'SmoothLineView_Example', :exclusive => true do 5 | pod "SmoothLineView", :path => "../" 6 | pod "PureLayout" 7 | end 8 | 9 | target 'Tests', :exclusive => true do 10 | pod "SmoothLineView", :path => "../" 11 | end 12 | -------------------------------------------------------------------------------- /Example/SmoothLineView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 11 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; 12 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 13 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; }; 14 | 6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; }; 15 | 6003F59E195388D20070C39A /* ENDAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* ENDAppDelegate.m */; }; 16 | 6003F5A1195388D20070C39A /* Main_iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6003F59F195388D20070C39A /* Main_iPhone.storyboard */; }; 17 | 6003F5A7195388D20070C39A /* ENDViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* ENDViewController.m */; }; 18 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; }; 19 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; 20 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; 21 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; 22 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; 23 | 6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; }; 24 | 65E29697497CC848030CF164 /* Pods_SmoothLineView_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD7114092886B8CB26362A90 /* Pods_SmoothLineView_Example.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 25 | 80B1ADC979C8EDD63924BFA6 /* Pods_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 394F7CF99C7A415FBB09F9E5 /* Pods_Tests.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 6003F582195388D10070C39A /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 6003F589195388D20070C39A; 34 | remoteInfo = SmoothLineView; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | 0D7EF7E7A733EB6E2216E4B0 /* SmoothLineView.podspec */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = SmoothLineView.podspec; path = ../SmoothLineView.podspec; sourceTree = ""; }; 40 | 297B627CC066946BBE2C2F75 /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; 41 | 394F7CF99C7A415FBB09F9E5 /* Pods_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 55707099A8B37FE6A1C67167 /* Pods-SmoothLineView_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SmoothLineView_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SmoothLineView_Example/Pods-SmoothLineView_Example.debug.xcconfig"; sourceTree = ""; }; 43 | 5A0415439F183F347FC5AD85 /* Pods-SmoothLineView_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SmoothLineView_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-SmoothLineView_Example/Pods-SmoothLineView_Example.release.xcconfig"; sourceTree = ""; }; 44 | 6003F58A195388D20070C39A /* SmoothLineView_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SmoothLineView_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 47 | 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | 6003F595195388D20070C39A /* SmoothLineView-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SmoothLineView-Info.plist"; sourceTree = ""; }; 49 | 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 50 | 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 6003F59B195388D20070C39A /* SmoothLineView-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SmoothLineView-Prefix.pch"; sourceTree = ""; }; 52 | 6003F59C195388D20070C39A /* ENDAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ENDAppDelegate.h; sourceTree = ""; }; 53 | 6003F59D195388D20070C39A /* ENDAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ENDAppDelegate.m; sourceTree = ""; }; 54 | 6003F5A0195388D20070C39A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main_iPhone.storyboard; sourceTree = ""; }; 55 | 6003F5A5195388D20070C39A /* ENDViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ENDViewController.h; sourceTree = ""; }; 56 | 6003F5A6195388D20070C39A /* ENDViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ENDViewController.m; sourceTree = ""; }; 57 | 6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 58 | 6003F5AE195388D20070C39A /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 60 | 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; 61 | 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 62 | 6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = ""; }; 63 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = ""; }; 64 | B11C29532654188806B98613 /* Pods-Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.debug.xcconfig"; sourceTree = ""; }; 65 | B4312A424CE3CFACBC12EB0B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../README.md; sourceTree = ""; }; 66 | DD7114092886B8CB26362A90 /* Pods_SmoothLineView_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SmoothLineView_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | DDF794FFF0A7ED35A9EC2AC2 /* Pods-Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests/Pods-Tests.release.xcconfig"; sourceTree = ""; }; 68 | /* End PBXFileReference section */ 69 | 70 | /* Begin PBXFrameworksBuildPhase section */ 71 | 6003F587195388D20070C39A /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, 76 | 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, 77 | 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, 78 | 65E29697497CC848030CF164 /* Pods_SmoothLineView_Example.framework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | 6003F5AB195388D20070C39A /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, 87 | 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, 88 | 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, 89 | 80B1ADC979C8EDD63924BFA6 /* Pods_Tests.framework in Frameworks */, 90 | ); 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | /* End PBXFrameworksBuildPhase section */ 94 | 95 | /* Begin PBXGroup section */ 96 | 45A58DA39A80853492AE3B81 /* Pods */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 55707099A8B37FE6A1C67167 /* Pods-SmoothLineView_Example.debug.xcconfig */, 100 | 5A0415439F183F347FC5AD85 /* Pods-SmoothLineView_Example.release.xcconfig */, 101 | B11C29532654188806B98613 /* Pods-Tests.debug.xcconfig */, 102 | DDF794FFF0A7ED35A9EC2AC2 /* Pods-Tests.release.xcconfig */, 103 | ); 104 | name = Pods; 105 | sourceTree = ""; 106 | }; 107 | 6003F581195388D10070C39A = { 108 | isa = PBXGroup; 109 | children = ( 110 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, 111 | 6003F593195388D20070C39A /* Example for SmoothLineView */, 112 | 6003F5B5195388D20070C39A /* Tests */, 113 | 6003F58C195388D20070C39A /* Frameworks */, 114 | 6003F58B195388D20070C39A /* Products */, 115 | 45A58DA39A80853492AE3B81 /* Pods */, 116 | ); 117 | sourceTree = ""; 118 | }; 119 | 6003F58B195388D20070C39A /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 6003F58A195388D20070C39A /* SmoothLineView_Example.app */, 123 | 6003F5AE195388D20070C39A /* Tests.xctest */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | 6003F58C195388D20070C39A /* Frameworks */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 6003F58D195388D20070C39A /* Foundation.framework */, 132 | 6003F58F195388D20070C39A /* CoreGraphics.framework */, 133 | 6003F591195388D20070C39A /* UIKit.framework */, 134 | 6003F5AF195388D20070C39A /* XCTest.framework */, 135 | DD7114092886B8CB26362A90 /* Pods_SmoothLineView_Example.framework */, 136 | 394F7CF99C7A415FBB09F9E5 /* Pods_Tests.framework */, 137 | ); 138 | name = Frameworks; 139 | sourceTree = ""; 140 | }; 141 | 6003F593195388D20070C39A /* Example for SmoothLineView */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 6003F59C195388D20070C39A /* ENDAppDelegate.h */, 145 | 6003F59D195388D20070C39A /* ENDAppDelegate.m */, 146 | 6003F59F195388D20070C39A /* Main_iPhone.storyboard */, 147 | 6003F5A5195388D20070C39A /* ENDViewController.h */, 148 | 6003F5A6195388D20070C39A /* ENDViewController.m */, 149 | 6003F5A8195388D20070C39A /* Images.xcassets */, 150 | 6003F594195388D20070C39A /* Supporting Files */, 151 | ); 152 | name = "Example for SmoothLineView"; 153 | path = SmoothLineView; 154 | sourceTree = ""; 155 | }; 156 | 6003F594195388D20070C39A /* Supporting Files */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 6003F595195388D20070C39A /* SmoothLineView-Info.plist */, 160 | 6003F596195388D20070C39A /* InfoPlist.strings */, 161 | 6003F599195388D20070C39A /* main.m */, 162 | 6003F59B195388D20070C39A /* SmoothLineView-Prefix.pch */, 163 | ); 164 | name = "Supporting Files"; 165 | sourceTree = ""; 166 | }; 167 | 6003F5B5195388D20070C39A /* Tests */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 6003F5BB195388D20070C39A /* Tests.m */, 171 | 6003F5B6195388D20070C39A /* Supporting Files */, 172 | ); 173 | path = Tests; 174 | sourceTree = ""; 175 | }; 176 | 6003F5B6195388D20070C39A /* Supporting Files */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 6003F5B7195388D20070C39A /* Tests-Info.plist */, 180 | 6003F5B8195388D20070C39A /* InfoPlist.strings */, 181 | 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */, 182 | ); 183 | name = "Supporting Files"; 184 | sourceTree = ""; 185 | }; 186 | 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { 187 | isa = PBXGroup; 188 | children = ( 189 | 0D7EF7E7A733EB6E2216E4B0 /* SmoothLineView.podspec */, 190 | B4312A424CE3CFACBC12EB0B /* README.md */, 191 | 297B627CC066946BBE2C2F75 /* LICENSE */, 192 | ); 193 | name = "Podspec Metadata"; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXGroup section */ 197 | 198 | /* Begin PBXNativeTarget section */ 199 | 6003F589195388D20070C39A /* SmoothLineView_Example */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "SmoothLineView_Example" */; 202 | buildPhases = ( 203 | 241E34AC1440B19670E98324 /* Check Pods Manifest.lock */, 204 | 6003F586195388D20070C39A /* Sources */, 205 | 6003F587195388D20070C39A /* Frameworks */, 206 | 6003F588195388D20070C39A /* Resources */, 207 | B6290503DF9720D4A96E8CAB /* Embed Pods Frameworks */, 208 | 02085128FB9A7ECE3F7F776D /* Copy Pods Resources */, 209 | ); 210 | buildRules = ( 211 | ); 212 | dependencies = ( 213 | ); 214 | name = SmoothLineView_Example; 215 | productName = SmoothLineView; 216 | productReference = 6003F58A195388D20070C39A /* SmoothLineView_Example.app */; 217 | productType = "com.apple.product-type.application"; 218 | }; 219 | 6003F5AD195388D20070C39A /* Tests */ = { 220 | isa = PBXNativeTarget; 221 | buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Tests" */; 222 | buildPhases = ( 223 | BFBEBCD81697E0EE3DC91502 /* Check Pods Manifest.lock */, 224 | 6003F5AA195388D20070C39A /* Sources */, 225 | 6003F5AB195388D20070C39A /* Frameworks */, 226 | 6003F5AC195388D20070C39A /* Resources */, 227 | 1F739E9B32A24165362AAE6F /* Embed Pods Frameworks */, 228 | 8E6700B8E67A7405A534A7A1 /* Copy Pods Resources */, 229 | ); 230 | buildRules = ( 231 | ); 232 | dependencies = ( 233 | 6003F5B4195388D20070C39A /* PBXTargetDependency */, 234 | ); 235 | name = Tests; 236 | productName = SmoothLineViewTests; 237 | productReference = 6003F5AE195388D20070C39A /* Tests.xctest */; 238 | productType = "com.apple.product-type.bundle.unit-test"; 239 | }; 240 | /* End PBXNativeTarget section */ 241 | 242 | /* Begin PBXProject section */ 243 | 6003F582195388D10070C39A /* Project object */ = { 244 | isa = PBXProject; 245 | attributes = { 246 | CLASSPREFIX = END; 247 | LastUpgradeCheck = 0510; 248 | ORGANIZATIONNAME = "Andreas Kompanez"; 249 | TargetAttributes = { 250 | 6003F5AD195388D20070C39A = { 251 | TestTargetID = 6003F589195388D20070C39A; 252 | }; 253 | }; 254 | }; 255 | buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "SmoothLineView" */; 256 | compatibilityVersion = "Xcode 3.2"; 257 | developmentRegion = English; 258 | hasScannedForEncodings = 0; 259 | knownRegions = ( 260 | en, 261 | Base, 262 | ); 263 | mainGroup = 6003F581195388D10070C39A; 264 | productRefGroup = 6003F58B195388D20070C39A /* Products */; 265 | projectDirPath = ""; 266 | projectRoot = ""; 267 | targets = ( 268 | 6003F589195388D20070C39A /* SmoothLineView_Example */, 269 | 6003F5AD195388D20070C39A /* Tests */, 270 | ); 271 | }; 272 | /* End PBXProject section */ 273 | 274 | /* Begin PBXResourcesBuildPhase section */ 275 | 6003F588195388D20070C39A /* Resources */ = { 276 | isa = PBXResourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, 280 | 6003F5A1195388D20070C39A /* Main_iPhone.storyboard in Resources */, 281 | 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | 6003F5AC195388D20070C39A /* Resources */ = { 286 | isa = PBXResourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | }; 293 | /* End PBXResourcesBuildPhase section */ 294 | 295 | /* Begin PBXShellScriptBuildPhase section */ 296 | 02085128FB9A7ECE3F7F776D /* Copy Pods Resources */ = { 297 | isa = PBXShellScriptBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | inputPaths = ( 302 | ); 303 | name = "Copy Pods Resources"; 304 | outputPaths = ( 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | shellPath = /bin/sh; 308 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SmoothLineView_Example/Pods-SmoothLineView_Example-resources.sh\"\n"; 309 | showEnvVarsInLog = 0; 310 | }; 311 | 1F739E9B32A24165362AAE6F /* Embed Pods Frameworks */ = { 312 | isa = PBXShellScriptBuildPhase; 313 | buildActionMask = 2147483647; 314 | files = ( 315 | ); 316 | inputPaths = ( 317 | ); 318 | name = "Embed Pods Frameworks"; 319 | outputPaths = ( 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | shellPath = /bin/sh; 323 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-frameworks.sh\"\n"; 324 | showEnvVarsInLog = 0; 325 | }; 326 | 241E34AC1440B19670E98324 /* Check Pods Manifest.lock */ = { 327 | isa = PBXShellScriptBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | ); 331 | inputPaths = ( 332 | ); 333 | name = "Check Pods Manifest.lock"; 334 | outputPaths = ( 335 | ); 336 | runOnlyForDeploymentPostprocessing = 0; 337 | shellPath = /bin/sh; 338 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 339 | showEnvVarsInLog = 0; 340 | }; 341 | 8E6700B8E67A7405A534A7A1 /* Copy Pods Resources */ = { 342 | isa = PBXShellScriptBuildPhase; 343 | buildActionMask = 2147483647; 344 | files = ( 345 | ); 346 | inputPaths = ( 347 | ); 348 | name = "Copy Pods Resources"; 349 | outputPaths = ( 350 | ); 351 | runOnlyForDeploymentPostprocessing = 0; 352 | shellPath = /bin/sh; 353 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests/Pods-Tests-resources.sh\"\n"; 354 | showEnvVarsInLog = 0; 355 | }; 356 | B6290503DF9720D4A96E8CAB /* Embed Pods Frameworks */ = { 357 | isa = PBXShellScriptBuildPhase; 358 | buildActionMask = 2147483647; 359 | files = ( 360 | ); 361 | inputPaths = ( 362 | ); 363 | name = "Embed Pods Frameworks"; 364 | outputPaths = ( 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | shellPath = /bin/sh; 368 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SmoothLineView_Example/Pods-SmoothLineView_Example-frameworks.sh\"\n"; 369 | showEnvVarsInLog = 0; 370 | }; 371 | BFBEBCD81697E0EE3DC91502 /* Check Pods Manifest.lock */ = { 372 | isa = PBXShellScriptBuildPhase; 373 | buildActionMask = 2147483647; 374 | files = ( 375 | ); 376 | inputPaths = ( 377 | ); 378 | name = "Check Pods Manifest.lock"; 379 | outputPaths = ( 380 | ); 381 | runOnlyForDeploymentPostprocessing = 0; 382 | shellPath = /bin/sh; 383 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 384 | showEnvVarsInLog = 0; 385 | }; 386 | /* End PBXShellScriptBuildPhase section */ 387 | 388 | /* Begin PBXSourcesBuildPhase section */ 389 | 6003F586195388D20070C39A /* Sources */ = { 390 | isa = PBXSourcesBuildPhase; 391 | buildActionMask = 2147483647; 392 | files = ( 393 | 6003F59E195388D20070C39A /* ENDAppDelegate.m in Sources */, 394 | 6003F5A7195388D20070C39A /* ENDViewController.m in Sources */, 395 | 6003F59A195388D20070C39A /* main.m in Sources */, 396 | ); 397 | runOnlyForDeploymentPostprocessing = 0; 398 | }; 399 | 6003F5AA195388D20070C39A /* Sources */ = { 400 | isa = PBXSourcesBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | 6003F5BC195388D20070C39A /* Tests.m in Sources */, 404 | ); 405 | runOnlyForDeploymentPostprocessing = 0; 406 | }; 407 | /* End PBXSourcesBuildPhase section */ 408 | 409 | /* Begin PBXTargetDependency section */ 410 | 6003F5B4195388D20070C39A /* PBXTargetDependency */ = { 411 | isa = PBXTargetDependency; 412 | target = 6003F589195388D20070C39A /* SmoothLineView_Example */; 413 | targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */; 414 | }; 415 | /* End PBXTargetDependency section */ 416 | 417 | /* Begin PBXVariantGroup section */ 418 | 6003F596195388D20070C39A /* InfoPlist.strings */ = { 419 | isa = PBXVariantGroup; 420 | children = ( 421 | 6003F597195388D20070C39A /* en */, 422 | ); 423 | name = InfoPlist.strings; 424 | sourceTree = ""; 425 | }; 426 | 6003F59F195388D20070C39A /* Main_iPhone.storyboard */ = { 427 | isa = PBXVariantGroup; 428 | children = ( 429 | 6003F5A0195388D20070C39A /* Base */, 430 | ); 431 | name = Main_iPhone.storyboard; 432 | sourceTree = ""; 433 | }; 434 | 6003F5B8195388D20070C39A /* InfoPlist.strings */ = { 435 | isa = PBXVariantGroup; 436 | children = ( 437 | 6003F5B9195388D20070C39A /* en */, 438 | ); 439 | name = InfoPlist.strings; 440 | sourceTree = ""; 441 | }; 442 | /* End PBXVariantGroup section */ 443 | 444 | /* Begin XCBuildConfiguration section */ 445 | 6003F5BD195388D20070C39A /* Debug */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_SEARCH_USER_PATHS = NO; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_MODULES = YES; 452 | CLANG_ENABLE_OBJC_ARC = YES; 453 | CLANG_WARN_BOOL_CONVERSION = YES; 454 | CLANG_WARN_CONSTANT_CONVERSION = YES; 455 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 456 | CLANG_WARN_EMPTY_BODY = YES; 457 | CLANG_WARN_ENUM_CONVERSION = YES; 458 | CLANG_WARN_INT_CONVERSION = YES; 459 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 460 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 461 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 462 | COPY_PHASE_STRIP = NO; 463 | GCC_C_LANGUAGE_STANDARD = gnu99; 464 | GCC_DYNAMIC_NO_PIC = NO; 465 | GCC_OPTIMIZATION_LEVEL = 0; 466 | GCC_PREPROCESSOR_DEFINITIONS = ( 467 | "DEBUG=1", 468 | "$(inherited)", 469 | ); 470 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 472 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 473 | GCC_WARN_UNDECLARED_SELECTOR = YES; 474 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 475 | GCC_WARN_UNUSED_FUNCTION = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 478 | ONLY_ACTIVE_ARCH = YES; 479 | SDKROOT = iphoneos; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 6003F5BE195388D20070C39A /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ALWAYS_SEARCH_USER_PATHS = NO; 488 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 489 | CLANG_CXX_LIBRARY = "libc++"; 490 | CLANG_ENABLE_MODULES = YES; 491 | CLANG_ENABLE_OBJC_ARC = YES; 492 | CLANG_WARN_BOOL_CONVERSION = YES; 493 | CLANG_WARN_CONSTANT_CONVERSION = YES; 494 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 495 | CLANG_WARN_EMPTY_BODY = YES; 496 | CLANG_WARN_ENUM_CONVERSION = YES; 497 | CLANG_WARN_INT_CONVERSION = YES; 498 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 499 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 500 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 501 | COPY_PHASE_STRIP = YES; 502 | ENABLE_NS_ASSERTIONS = NO; 503 | GCC_C_LANGUAGE_STANDARD = gnu99; 504 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 505 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 506 | GCC_WARN_UNDECLARED_SELECTOR = YES; 507 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 508 | GCC_WARN_UNUSED_FUNCTION = YES; 509 | GCC_WARN_UNUSED_VARIABLE = YES; 510 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 511 | SDKROOT = iphoneos; 512 | TARGETED_DEVICE_FAMILY = "1,2"; 513 | VALIDATE_PRODUCT = YES; 514 | }; 515 | name = Release; 516 | }; 517 | 6003F5C0195388D20070C39A /* Debug */ = { 518 | isa = XCBuildConfiguration; 519 | baseConfigurationReference = 55707099A8B37FE6A1C67167 /* Pods-SmoothLineView_Example.debug.xcconfig */; 520 | buildSettings = { 521 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 522 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 523 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 524 | GCC_PREFIX_HEADER = "SmoothLineView/SmoothLineView-Prefix.pch"; 525 | INFOPLIST_FILE = "SmoothLineView/SmoothLineView-Info.plist"; 526 | MODULE_NAME = ExampleApp; 527 | PRODUCT_NAME = "$(TARGET_NAME)"; 528 | TARGETED_DEVICE_FAMILY = 1; 529 | WRAPPER_EXTENSION = app; 530 | }; 531 | name = Debug; 532 | }; 533 | 6003F5C1195388D20070C39A /* Release */ = { 534 | isa = XCBuildConfiguration; 535 | baseConfigurationReference = 5A0415439F183F347FC5AD85 /* Pods-SmoothLineView_Example.release.xcconfig */; 536 | buildSettings = { 537 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 538 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 539 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 540 | GCC_PREFIX_HEADER = "SmoothLineView/SmoothLineView-Prefix.pch"; 541 | INFOPLIST_FILE = "SmoothLineView/SmoothLineView-Info.plist"; 542 | MODULE_NAME = ExampleApp; 543 | PRODUCT_NAME = "$(TARGET_NAME)"; 544 | TARGETED_DEVICE_FAMILY = 1; 545 | WRAPPER_EXTENSION = app; 546 | }; 547 | name = Release; 548 | }; 549 | 6003F5C3195388D20070C39A /* Debug */ = { 550 | isa = XCBuildConfiguration; 551 | baseConfigurationReference = B11C29532654188806B98613 /* Pods-Tests.debug.xcconfig */; 552 | buildSettings = { 553 | BUNDLE_LOADER = "$(TEST_HOST)"; 554 | FRAMEWORK_SEARCH_PATHS = ( 555 | "$(SDKROOT)/Developer/Library/Frameworks", 556 | "$(inherited)", 557 | "$(DEVELOPER_FRAMEWORKS_DIR)", 558 | ); 559 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 560 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 561 | GCC_PREPROCESSOR_DEFINITIONS = ( 562 | "DEBUG=1", 563 | "$(inherited)", 564 | ); 565 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SmoothLineView_Example.app/SmoothLineView_Example"; 568 | WRAPPER_EXTENSION = xctest; 569 | }; 570 | name = Debug; 571 | }; 572 | 6003F5C4195388D20070C39A /* Release */ = { 573 | isa = XCBuildConfiguration; 574 | baseConfigurationReference = DDF794FFF0A7ED35A9EC2AC2 /* Pods-Tests.release.xcconfig */; 575 | buildSettings = { 576 | BUNDLE_LOADER = "$(TEST_HOST)"; 577 | FRAMEWORK_SEARCH_PATHS = ( 578 | "$(SDKROOT)/Developer/Library/Frameworks", 579 | "$(inherited)", 580 | "$(DEVELOPER_FRAMEWORKS_DIR)", 581 | ); 582 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 583 | GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; 584 | INFOPLIST_FILE = "Tests/Tests-Info.plist"; 585 | PRODUCT_NAME = "$(TARGET_NAME)"; 586 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SmoothLineView_Example.app/SmoothLineView_Example"; 587 | WRAPPER_EXTENSION = xctest; 588 | }; 589 | name = Release; 590 | }; 591 | /* End XCBuildConfiguration section */ 592 | 593 | /* Begin XCConfigurationList section */ 594 | 6003F585195388D10070C39A /* Build configuration list for PBXProject "SmoothLineView" */ = { 595 | isa = XCConfigurationList; 596 | buildConfigurations = ( 597 | 6003F5BD195388D20070C39A /* Debug */, 598 | 6003F5BE195388D20070C39A /* Release */, 599 | ); 600 | defaultConfigurationIsVisible = 0; 601 | defaultConfigurationName = Release; 602 | }; 603 | 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "SmoothLineView_Example" */ = { 604 | isa = XCConfigurationList; 605 | buildConfigurations = ( 606 | 6003F5C0195388D20070C39A /* Debug */, 607 | 6003F5C1195388D20070C39A /* Release */, 608 | ); 609 | defaultConfigurationIsVisible = 0; 610 | defaultConfigurationName = Release; 611 | }; 612 | 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "Tests" */ = { 613 | isa = XCConfigurationList; 614 | buildConfigurations = ( 615 | 6003F5C3195388D20070C39A /* Debug */, 616 | 6003F5C4195388D20070C39A /* Release */, 617 | ); 618 | defaultConfigurationIsVisible = 0; 619 | defaultConfigurationName = Release; 620 | }; 621 | /* End XCConfigurationList section */ 622 | }; 623 | rootObject = 6003F582195388D10070C39A /* Project object */; 624 | } 625 | -------------------------------------------------------------------------------- /Example/SmoothLineView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/SmoothLineView.xcodeproj/xcshareddata/xcschemes/SmoothLineView-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 63 | 69 | 70 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Example/SmoothLineView.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/SmoothLineView/Base.lproj/Main_iPhone.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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Example/SmoothLineView/ENDAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDAppDelegate.h 3 | // SmoothLineView 4 | // 5 | // Created by CocoaPods on 05/27/2015. 6 | // Copyright (c) 2014 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ENDAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/SmoothLineView/ENDAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDAppDelegate.m 3 | // SmoothLineView 4 | // 5 | // Created by CocoaPods on 05/27/2015. 6 | // Copyright (c) 2014 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | #import "ENDAppDelegate.h" 10 | 11 | @implementation ENDAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Example/SmoothLineView/ENDViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDViewController.h 3 | // SmoothLineView 4 | // 5 | // Created by Andreas Kompanez on 05/27/2015. 6 | // Copyright (c) 2014 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface ENDViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/SmoothLineView/ENDViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDViewController.m 3 | // SmoothLineView 4 | // 5 | // Created by Andreas Kompanez on 05/27/2015. 6 | // Copyright (c) 2014 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | #import "ENDViewController.h" 10 | 11 | #import 12 | #import 13 | #import 14 | 15 | 16 | 17 | @interface ENDViewController () 18 | 19 | @property (nonatomic, strong) LVSmoothLineView *smoothLineView; 20 | @property (weak, nonatomic) IBOutlet UIToolbar *toolbar; 21 | 22 | @end 23 | 24 | @implementation ENDViewController 25 | 26 | - (void)viewDidLoad 27 | { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view, typically from a nib. 30 | 31 | self.smoothLineView = [[LVSmoothLineView alloc] initForAutoLayout]; 32 | self.smoothLineView.delegate = self; 33 | [self.view addSubview:self.smoothLineView]; 34 | 35 | [self.smoothLineView autoPinEdgesToSuperviewEdgesWithInsets:(ALEdgeInsets){0, 0, self.toolbar.frame.size.height, 0}]; 36 | 37 | [self pickRedColor:nil]; 38 | } 39 | 40 | - (void)didReceiveMemoryWarning 41 | { 42 | [super didReceiveMemoryWarning]; 43 | // Dispose of any resources that can be recreated. 44 | } 45 | 46 | -(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event 47 | { 48 | [self.smoothLineView undo]; 49 | } 50 | 51 | - (void)smoothLineViewLongPressed:(LVSmoothLineView *)view 52 | { 53 | UIColor *color = self.smoothLineView.brush.color; 54 | [self.smoothLineView fillWithColor:color]; 55 | } 56 | 57 | - (IBAction)undo:(id)sender 58 | { 59 | [self.smoothLineView undo]; 60 | } 61 | 62 | - (IBAction)redo:(id)sender 63 | { 64 | [self.smoothLineView redo]; 65 | } 66 | 67 | - (IBAction)pickRedColor:(id)sender 68 | { 69 | self.smoothLineView.brush.color = [UIColor redColor]; 70 | } 71 | 72 | - (IBAction)pickGreenColor:(id)sender 73 | { 74 | self.smoothLineView.brush.color = [UIColor greenColor]; 75 | } 76 | 77 | - (IBAction)pickBlueColor:(id)sender 78 | { 79 | self.smoothLineView.brush.color = [UIColor blueColor]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Example/SmoothLineView/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 | } 54 | -------------------------------------------------------------------------------- /Example/SmoothLineView/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 | } 52 | -------------------------------------------------------------------------------- /Example/SmoothLineView/SmoothLineView-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier} 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 | Main_iPhone 29 | UIMainStoryboardFile~ipad 30 | Main_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/SmoothLineView/SmoothLineView-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_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/SmoothLineView/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/SmoothLineView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SmoothLineView 4 | // 5 | // Created by Andreas Kompanez on 05/27/2015. 6 | // Copyright (c) 2014 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "ENDAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ENDAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | @import FBSnapshotTestCase; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SmoothLineViewTests.m 3 | // SmoothLineViewTests 4 | // 5 | // Created by Andreas Kompanez on 05/27/2015. 6 | // Copyright (c) 2015 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.endlessnumbered.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Levi Nunnink 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Pod/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kompozer/SmoothLineView/2166fd4b573e01aadc6b0832b9aa9bfe3b8bb358/Pod/Assets/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kompozer/SmoothLineView/2166fd4b573e01aadc6b0832b9aa9bfe3b8bb358/Pod/Classes/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/ENDBrush.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDBrush.h 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @class ENDBrushShadow; 12 | 13 | 14 | 15 | @interface ENDBrush : NSObject 16 | 17 | @property (nonatomic, strong) UIColor *color; 18 | @property (nonatomic, assign) CGFloat lineWidth; 19 | /// Per default not set 20 | @property (nonatomic, strong) ENDBrushShadow *shadow; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Pod/Classes/ENDBrush.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDBrush.m 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import "ENDBrush.h" 10 | 11 | #import "ENDBrushShadow.h" 12 | 13 | 14 | 15 | @implementation ENDBrush 16 | 17 | - (instancetype)init 18 | { 19 | self = [super init]; 20 | if (self) { 21 | self.lineWidth = 8.0; 22 | self.color = [UIColor blackColor]; 23 | } 24 | return self; 25 | } 26 | 27 | - (id)copyWithZone:(NSZone *)zone 28 | { 29 | ENDBrush *newBrush = [[[self class] allocWithZone:zone] init]; 30 | newBrush.color = self.color; 31 | newBrush.lineWidth = self.lineWidth; 32 | newBrush.shadow = self.shadow; 33 | 34 | return newBrush; 35 | } 36 | 37 | - (BOOL)isEqual:(id)object 38 | { 39 | if (![object isKindOfClass:[ENDBrush class]]) { 40 | return NO; 41 | } 42 | 43 | ENDBrush *other = object; 44 | 45 | return fabs(other.lineWidth - self.lineWidth) < 0.01 && 46 | [other.color isEqual:self.color] && 47 | [other.shadow isEqual:self.shadow]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Pod/Classes/ENDBrushShadow.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDBrushShadow.h 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @interface ENDBrushShadow : NSObject 14 | 15 | @property (nonatomic, assign) CGSize offset; 16 | @property (nonatomic, assign) CGFloat blur; 17 | @property (nonatomic, strong) UIColor *color; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Pod/Classes/ENDBrushShadow.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDBrushShadow.m 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import "ENDBrushShadow.h" 10 | 11 | 12 | 13 | @implementation ENDBrushShadow 14 | 15 | - (instancetype)init 16 | { 17 | self = [super init]; 18 | if (self) { 19 | self.blur = 0.6; 20 | self.color = [UIColor grayColor]; 21 | self.offset = (CGSize){0.5, 0.5}; 22 | } 23 | return self; 24 | } 25 | 26 | - (BOOL)isEqual:(id)object 27 | { 28 | if (![object isKindOfClass:[ENDBrushShadow class]]) { 29 | return NO; 30 | } 31 | 32 | ENDBrushShadow *other = object; 33 | 34 | 35 | return fabs(other.blur - self.blur) < 0.01 && 36 | [other.color isEqual:self.color] && 37 | CGSizeEqualToSize(other.offset, self.offset); 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawFillWithColorOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawFillWithColorOperation.h 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "ENDDrawOperation.h" 12 | 13 | 14 | 15 | @interface ENDDrawFillWithColorOperation : NSObject 16 | 17 | @property (nonatomic, assign) CGRect fillRect; 18 | 19 | /// The fill color 20 | @property (nonatomic, strong) UIColor *color; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawFillWithColorOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawFillWithColorOperation.m 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import "ENDDrawFillWithColorOperation.h" 10 | 11 | 12 | 13 | @interface ENDDrawFillWithColorOperation () 14 | 15 | @end 16 | 17 | @implementation ENDDrawFillWithColorOperation 18 | @synthesize sequenceID; 19 | 20 | - (void)drawInContext:(CGContextRef)context inRect:(CGRect)rect 21 | { 22 | if (self.color) { 23 | [self.color set]; 24 | UIRectFill(rect); 25 | } 26 | } 27 | 28 | - (CGRect)drawRect 29 | { 30 | return self.fillRect; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawGestureRecognizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawGestureRecognizer.h 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 31.05.15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @interface ENDDrawGestureRecognizer : UIGestureRecognizer 14 | 15 | @property (nonatomic, strong, readonly) NSSet *touches; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawGestureRecognizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawGestureRecognizer.m 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 31.05.15. 6 | // 7 | // 8 | 9 | #import "ENDDrawGestureRecognizer.h" 10 | 11 | #import 12 | 13 | 14 | 15 | @interface ENDDrawGestureRecognizer () 16 | 17 | @property (nonatomic, strong, readwrite) NSSet *touches; 18 | 19 | @end 20 | 21 | @implementation ENDDrawGestureRecognizer 22 | 23 | - (void)reset 24 | { 25 | [super reset]; 26 | self.touches = nil; 27 | } 28 | 29 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 30 | { 31 | [super touchesBegan:touches withEvent:event]; 32 | self.touches = [NSSet setWithSet:touches]; 33 | self.state = UIGestureRecognizerStateBegan; 34 | } 35 | 36 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 37 | { 38 | [super touchesMoved:touches withEvent:event]; 39 | self.touches = [NSSet setWithSet:touches]; 40 | self.state = UIGestureRecognizerStateChanged; 41 | } 42 | 43 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 44 | { 45 | [super touchesEnded:touches withEvent:event]; 46 | self.touches = [NSSet setWithSet:touches]; 47 | self.state = UIGestureRecognizerStateEnded; 48 | } 49 | 50 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 51 | { 52 | [super touchesEnded:touches withEvent:event]; 53 | self.state = UIGestureRecognizerStateCancelled; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawOperation.h 3 | // Smooth Line View 4 | // 5 | // Created by Andreas Kompanez on 26.05.15. 6 | // Copyright (c) 2015 culturezoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @protocol ENDDrawOperation 14 | 15 | @property (nonatomic) NSUInteger sequenceID; 16 | @property (nonatomic, readonly) CGRect drawRect; 17 | 18 | /// @param context The drawing context 19 | /// @param rect The draw rect 20 | - (void)drawInContext:(CGContextRef)context inRect:(CGRect)rect; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawPathOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawPathOperation.h 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #import "ENDDrawOperation.h" 12 | 13 | @class ENDDrawPathShadow; 14 | @class ENDBrush; 15 | 16 | 17 | 18 | @interface ENDDrawPathOperation : NSObject 19 | 20 | @property (nonatomic, copy) ENDBrush *brush; 21 | @property (nonatomic, copy, readonly) UIBezierPath *path; 22 | 23 | - (void)addSubpath:(UIBezierPath *)subpath; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawPathOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawPathOperation.m 3 | // Pods 4 | // 5 | // Created by Andreas Kompanez on 21.06.15. 6 | // 7 | // 8 | 9 | #import "ENDDrawPathOperation.h" 10 | 11 | #import "ENDBrush.h" 12 | #import "ENDBrushShadow.h" 13 | 14 | 15 | 16 | @interface ENDDrawPathOperation () 17 | 18 | @property (nonatomic, strong) UIBezierPath *internalPath; 19 | 20 | @end 21 | 22 | @implementation ENDDrawPathOperation 23 | @synthesize sequenceID; 24 | 25 | - (instancetype)init 26 | { 27 | self = [super init]; 28 | if (self) { 29 | self.internalPath = [UIBezierPath bezierPath]; 30 | } 31 | return self; 32 | } 33 | 34 | - (UIBezierPath *)path 35 | { 36 | return [self.internalPath copy]; 37 | } 38 | 39 | - (void)drawInContext:(CGContextRef)context inRect:(CGRect)rect 40 | { 41 | #pragma unused(rect) 42 | UIBezierPath *path = self.path; 43 | 44 | CGContextSetLineCap(context, kCGLineCapRound); 45 | CGContextSetLineWidth(context, self.brush.lineWidth); 46 | 47 | CGContextAddPath(context, path.CGPath); 48 | CGContextSetStrokeColorWithColor(context, self.brush.color.CGColor); 49 | if (self.brush.shadow) { 50 | CGContextSetShadowWithColor(context, self.brush.shadow.offset, self.brush.shadow.blur, self.brush.shadow.color.CGColor); 51 | } 52 | 53 | CGContextStrokePath(context); 54 | } 55 | 56 | - (CGRect)pathDrawBox:(CGPathRef)path 57 | { 58 | if (! path) { 59 | return CGRectNull; 60 | } 61 | 62 | CGRect bounds = CGPathGetBoundingBox(path); 63 | CGRect pathDrawBox = CGRectInset(bounds, -2.0 * self.brush.lineWidth, -2.0 * self.brush.lineWidth); 64 | 65 | return pathDrawBox; 66 | } 67 | 68 | - (CGRect)drawRect 69 | { 70 | return [self pathDrawBox:[self.path CGPath]]; 71 | } 72 | 73 | - (void)addSubpath:(UIBezierPath *)subpath 74 | { 75 | if (subpath) { 76 | [self.internalPath appendPath:subpath]; 77 | } 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawSession.h: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawSession.h 3 | // Smooth Line View 4 | // 5 | // Created by Andreas Kompanez on 26.05.15. 6 | // Copyright (c) 2015 culturezoo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol ENDDrawOperation; 12 | 13 | 14 | 15 | @interface ENDDrawSession : NSObject 16 | 17 | /// Current running operation 18 | @property (nonatomic, strong, readonly) id operation; 19 | @property (nonatomic, copy, readonly) NSArray *operations; 20 | 21 | - (id )beginOperation:(Class)operationClass; 22 | - (id )beginOperation:(Class)operationClass inSequence:(BOOL)inSequence; 23 | - (void)endOperation; 24 | 25 | - (BOOL)canRemoveLastOperation; 26 | - (void)removeLastOperation; 27 | 28 | - (BOOL)canRedoLastOperation; 29 | - (void)redoLastOperation; 30 | 31 | - (void)removeAllOperations; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Pod/Classes/ENDDrawSession.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawSession.m 3 | // Smooth Line View 4 | // 5 | // Created by Andreas Kompanez on 26.05.15. 6 | // Copyright (c) 2015 culturezoo. All rights reserved. 7 | // 8 | 9 | #import "ENDDrawSession.h" 10 | 11 | #import "ENDDrawOperation.h" 12 | 13 | 14 | 15 | @interface ENDDrawSession () 16 | 17 | @property (nonatomic, strong, readwrite) id operation; 18 | 19 | @property (nonatomic, strong) NSMutableArray *internalOperations; 20 | @property (nonatomic, strong) NSMutableArray *redoOperations; 21 | 22 | @property (nonatomic) NSUInteger lastSequenceID; 23 | @end 24 | 25 | @implementation ENDDrawSession 26 | 27 | - (instancetype)init 28 | { 29 | self = [super init]; 30 | if (self) { 31 | self.internalOperations = [NSMutableArray new]; 32 | self.redoOperations = [NSMutableArray new]; 33 | } 34 | return self; 35 | } 36 | 37 | - (NSArray *)operations 38 | { 39 | return [NSArray arrayWithArray:self.internalOperations]; 40 | } 41 | 42 | - (id )beginOperation:(Class)operationClass 43 | { 44 | return [self beginOperation:operationClass inSequence:NO]; 45 | } 46 | 47 | - (id )beginOperation:(Class)operationClass inSequence:(BOOL)inSequence 48 | { 49 | if (! [operationClass conformsToProtocol:@protocol(ENDDrawOperation)]) { 50 | return nil; 51 | } 52 | self.operation = [operationClass new]; 53 | self.operation.sequenceID = inSequence ? self.lastSequenceID : self.lastSequenceID + 1; 54 | return self.operation; 55 | } 56 | 57 | - (void)endOperation 58 | { 59 | if (self.operation) { 60 | [self.internalOperations addObject:self.operation]; 61 | self.operation = nil; 62 | 63 | [self.redoOperations removeAllObjects]; 64 | } 65 | } 66 | 67 | - (BOOL)canRemoveLastOperation 68 | { 69 | return (self.internalOperations.count > 0); 70 | } 71 | 72 | - (void)removeLastOperation 73 | { 74 | if (self.internalOperations.count == 0) { 75 | return; 76 | } 77 | 78 | id operation = [self.internalOperations lastObject]; 79 | [self.internalOperations removeObject:operation]; 80 | [self.redoOperations addObject:operation]; 81 | 82 | NSUInteger lastOperationSequenceID = operation.sequenceID; 83 | 84 | operation = [self.internalOperations lastObject]; 85 | 86 | while(operation.sequenceID == lastOperationSequenceID) { 87 | [self.internalOperations removeObject:operation]; 88 | [self.redoOperations addObject:operation]; 89 | operation = [self.internalOperations lastObject]; 90 | }; 91 | } 92 | 93 | - (BOOL)canRedoLastOperation 94 | { 95 | return (self.redoOperations.count > 0); 96 | } 97 | 98 | - (void)redoLastOperation 99 | { 100 | if (self.redoOperations.count == 0) { 101 | return; 102 | } 103 | id operation = [self.redoOperations lastObject]; 104 | [self.internalOperations addObject:operation]; 105 | [self.redoOperations removeObject:operation]; 106 | 107 | NSUInteger lastOperationSequenceID = operation.sequenceID; 108 | 109 | operation = [self.redoOperations lastObject]; 110 | 111 | while(operation.sequenceID == lastOperationSequenceID) { 112 | [self.internalOperations addObject:operation]; 113 | [self.redoOperations removeObject:operation]; 114 | operation = [self.redoOperations lastObject]; 115 | }; 116 | } 117 | 118 | - (void)removeAllOperations 119 | { 120 | [self.internalOperations removeAllObjects]; 121 | [self.redoOperations removeAllObjects]; 122 | } 123 | 124 | - (NSUInteger)lastSequenceID 125 | { 126 | id operation = self.internalOperations.lastObject; 127 | return operation.sequenceID; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /Pod/Classes/LVSmoothLineView.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2013 Levi Nunnink 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | // the Software, and to permit persons to whom the Software is furnished to do so, 10 | // 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, FITNESS 17 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // 23 | // Created by Levi Nunnink (@a_band) http://culturezoo.com 24 | // Copyright (C) Droplr Inc. All Rights Reserved 25 | // 26 | 27 | #import 28 | 29 | @protocol LVSmoothLineViewDelegate; 30 | @class ENDBrush; 31 | 32 | 33 | 34 | @interface LVSmoothLineView : UIView 35 | 36 | @property (nonatomic, weak) id delegate; 37 | @property (nonatomic, strong) ENDBrush *brush; 38 | 39 | /// Fills the canvas with the given @c color. This operation can be undone with the @c undo method 40 | - (void)fillWithColor:(UIColor *)color; 41 | 42 | - (void)clear; 43 | 44 | - (BOOL)canUndo; 45 | - (void)undo; 46 | 47 | - (BOOL)canRedo; 48 | - (void)redo; 49 | 50 | @end 51 | 52 | 53 | 54 | @interface LVSmoothLineView (Snapshot) 55 | 56 | - (UIImage *)snapshotImage; 57 | - (CGRect)drawingBox; 58 | 59 | @end 60 | 61 | 62 | 63 | @protocol LVSmoothLineViewDelegate 64 | 65 | - (void)smoothLineViewLongPressed:(LVSmoothLineView *)view; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Pod/Classes/LVSmoothLineView.m: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2013 Levi Nunnink 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | // the Software, and to permit persons to whom the Software is furnished to do so, 10 | // 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, FITNESS 17 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // 23 | // Created by Levi Nunnink (@a_band) http://culturezoo.com 24 | // Copyright (C) Droplr Inc. All Rights Reserved 25 | // 26 | 27 | #import "LVSmoothLineView.h" 28 | 29 | #import 30 | 31 | #import "ENDDrawOperation.h" 32 | #import "ENDDrawSession.h" 33 | #import "ENDDrawGestureRecognizer.h" 34 | #import "ENDDrawPathOperation.h" 35 | #import "ENDDrawFillWithColorOperation.h" 36 | #import "ENDBrush.h" 37 | 38 | 39 | 40 | static UIColor *LVDefaultBackgroundColor = nil; 41 | static const CGFloat LVPointMinDistance = 4.0f; 42 | static const CGFloat LVPointMinDistanceSquared = LVPointMinDistance * LVPointMinDistance; 43 | 44 | #pragma mark private Helper function 45 | 46 | static CGPoint LVMiddlePoint(CGPoint p1, CGPoint p2) { 47 | return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5); 48 | } 49 | 50 | 51 | @interface LVSmoothLineView () 52 | 53 | @property (nonatomic, assign) CGPoint currentPoint; 54 | @property (nonatomic, assign) CGPoint previousPoint; 55 | @property (nonatomic, assign) CGPoint previousPreviousPoint; 56 | 57 | @property (nonatomic, strong) ENDDrawPathOperation *pathOperation; 58 | @property (nonatomic, strong) ENDDrawSession *session; 59 | 60 | @end 61 | 62 | @implementation LVSmoothLineView 63 | 64 | + (void)initialize 65 | { 66 | LVDefaultBackgroundColor = [UIColor whiteColor]; 67 | } 68 | 69 | #pragma mark UIView lifecycle methods 70 | 71 | - (id)initWithCoder:(NSCoder *)aDecoder 72 | { 73 | self = [super initWithCoder:aDecoder]; 74 | 75 | if (self) { 76 | // NOTE: do not change the backgroundColor here, so it can be set in IB. 77 | [self setUpSmoothLineView]; 78 | } 79 | 80 | return self; 81 | } 82 | 83 | - (id)initWithFrame:(CGRect)frame 84 | { 85 | self = [super initWithFrame:frame]; 86 | 87 | if (self) { 88 | self.backgroundColor = LVDefaultBackgroundColor; 89 | 90 | [self setUpSmoothLineView]; 91 | } 92 | 93 | return self; 94 | } 95 | 96 | - (void)setUpSmoothLineView 97 | { 98 | self.session = [ENDDrawSession new]; 99 | self.brush = [ENDBrush new]; 100 | 101 | UIGestureRecognizer *recognizer = [[ENDDrawGestureRecognizer alloc] initWithTarget:self action:@selector(drawGestureRecognized:)]; 102 | [self addGestureRecognizer:recognizer]; 103 | 104 | UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressRecognized:)]; 105 | longPressRecognizer.minimumPressDuration = 0.6; 106 | [self addGestureRecognizer:longPressRecognizer]; 107 | 108 | [recognizer requireGestureRecognizerToFail:longPressRecognizer]; 109 | } 110 | 111 | - (void)drawRect:(CGRect)rect 112 | { 113 | // clear rect 114 | [self.backgroundColor set]; 115 | UIRectFill(rect); 116 | 117 | // get the graphics context and draw the path 118 | CGContextRef context = UIGraphicsGetCurrentContext(); 119 | 120 | CGContextSetBlendMode(context, kCGBlendModeNormal); 121 | CGContextSetShouldAntialias(context, YES); 122 | CGContextSetAllowsAntialiasing(context, YES); 123 | CGContextSetFlatness(context, 0.1f); 124 | 125 | // Append the current running operation, so we can draw it 126 | NSMutableArray *operations = [self.session.operations mutableCopy]; 127 | if (self.session.operation) { 128 | [operations addObject:self.session.operation]; 129 | } 130 | 131 | for (id operation in operations) { 132 | [operation drawInContext:context inRect:rect]; 133 | } 134 | } 135 | 136 | #pragma mark Touch handling 137 | 138 | - (void)drawGestureRecognized:(ENDDrawGestureRecognizer *)recognizer 139 | { 140 | NSSet *touches = recognizer.touches; 141 | // No support for multi touch gestures 142 | if (recognizer.numberOfTouches > 1) { 143 | return; 144 | } 145 | 146 | if (recognizer.state == UIGestureRecognizerStateBegan || recognizer.state == UIGestureRecognizerStateChanged) { 147 | [self drawOperationMoved:touches]; 148 | } 149 | else if (recognizer.state == UIGestureRecognizerStateEnded) { 150 | [self drawOperationEnded:touches]; 151 | } 152 | } 153 | 154 | - (void)drawOperationMoved:(NSSet *)touches 155 | { 156 | UITouch *touch = [touches anyObject]; 157 | 158 | ENDBrush *proposedBrush = nil; 159 | 160 | if ([touch respondsToSelector:@selector(force)] && fabs([touch force] - 1.0f) > 0.01 && [touch maximumPossibleForce] != 0) { 161 | proposedBrush = [self.brush copy]; 162 | proposedBrush.lineWidth = self.brush.lineWidth * ([touch force] / [touch maximumPossibleForce]) * 4.0f; 163 | } 164 | else { 165 | proposedBrush = [self.brush copy]; 166 | } 167 | 168 | if (self.pathOperation == nil) { 169 | self.pathOperation = [self.session beginOperation:[ENDDrawPathOperation class] inSequence:NO]; 170 | self.pathOperation.brush = proposedBrush; 171 | 172 | // initializes our point records to current location 173 | self.previousPoint = [touch previousLocationInView:self]; 174 | self.previousPreviousPoint = [touch previousLocationInView:self]; 175 | self.currentPoint = [touch locationInView:self]; 176 | } 177 | else { 178 | if (proposedBrush != nil && ![self.brush isEqual:proposedBrush]) { 179 | [self drawOperationEnded:touches]; 180 | 181 | self.pathOperation = [self.session beginOperation:[ENDDrawPathOperation class] inSequence:YES]; 182 | self.pathOperation.brush = proposedBrush; 183 | } 184 | } 185 | 186 | CGPoint point = [touch locationInView:self]; 187 | 188 | // if the finger has moved less than the min dist ... 189 | CGFloat dx = point.x - self.currentPoint.x; 190 | CGFloat dy = point.y - self.currentPoint.y; 191 | CGFloat distance = (dx * dx + dy * dy); 192 | 193 | if ((distance > 0) && (distance < LVPointMinDistanceSquared)) { 194 | // ... then ignore this movement 195 | return; 196 | } 197 | 198 | // update points: previousPrevious -> mid1 -> previous -> mid2 -> current 199 | self.previousPreviousPoint = self.previousPoint; 200 | self.previousPoint = self.currentPoint; 201 | self.currentPoint = [touch locationInView:self]; 202 | 203 | CGPoint mid1 = LVMiddlePoint(self.previousPoint, self.previousPreviousPoint); 204 | CGPoint mid2 = LVMiddlePoint(self.currentPoint, self.previousPoint); 205 | 206 | // to represent the finger movement, create a new path segment, 207 | // a quadratic bezier path from mid1 to mid2, using previous as a control point 208 | CGMutablePathRef subpath = CGPathCreateMutable(); 209 | CGPathMoveToPoint(subpath, NULL, mid1.x, mid1.y); 210 | CGPathAddQuadCurveToPoint(subpath, NULL, 211 | self.previousPoint.x, self.previousPoint.y, 212 | mid2.x, mid2.y); 213 | 214 | [self.pathOperation addSubpath:[UIBezierPath bezierPathWithCGPath:subpath]]; 215 | 216 | CGPathRelease(subpath); 217 | 218 | // compute the rect containing the new segment plus padding for drawn line 219 | CGRect drawBox = [self.pathOperation drawRect]; 220 | 221 | [self setNeedsDisplayInRect:drawBox]; 222 | } 223 | 224 | - (void)drawOperationEnded:(NSSet *)touches 225 | { 226 | [self.session endOperation]; 227 | self.pathOperation = nil; 228 | } 229 | 230 | - (void)longPressRecognized:(UILongPressGestureRecognizer *)recognizer 231 | { 232 | if (recognizer.state == UIGestureRecognizerStateBegan && [self.delegate respondsToSelector:@selector(smoothLineViewLongPressed:)]) { 233 | [self.delegate smoothLineViewLongPressed:self]; 234 | } 235 | } 236 | 237 | #pragma mark interface 238 | 239 | - (BOOL)canUndo 240 | { 241 | return [self.session canRemoveLastOperation]; 242 | } 243 | 244 | - (void)undo 245 | { 246 | if (! [self canUndo]) { 247 | return; 248 | } 249 | 250 | [self.session removeLastOperation]; 251 | [self setNeedsDisplay]; 252 | } 253 | 254 | - (BOOL)canRedo 255 | { 256 | return [self.session canRedoLastOperation]; 257 | } 258 | 259 | - (void)redo 260 | { 261 | if (! [self canRedo]) { 262 | return; 263 | } 264 | 265 | [self.session redoLastOperation]; 266 | [self setNeedsDisplay]; 267 | } 268 | 269 | - (void)clear 270 | { 271 | [self.session removeAllOperations]; 272 | [self setNeedsDisplay]; 273 | } 274 | 275 | - (void)fillWithColor:(UIColor *)color 276 | { 277 | if (! color) { 278 | return; 279 | } 280 | ENDDrawFillWithColorOperation *fillOperation = [self.session beginOperation:[ENDDrawFillWithColorOperation class] inSequence:NO]; 281 | fillOperation.color = color; 282 | fillOperation.fillRect = self.bounds; 283 | 284 | [self.session endOperation]; 285 | 286 | [self setNeedsDisplay]; 287 | } 288 | 289 | @end 290 | 291 | @implementation LVSmoothLineView (Snapshot) 292 | 293 | - (UIImage *)snapshotImage 294 | { 295 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, self.opaque, 0.0); 296 | [self.layer renderInContext:UIGraphicsGetCurrentContext()]; 297 | 298 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 299 | 300 | UIGraphicsEndImageContext(); 301 | return image; 302 | } 303 | 304 | - (CGRect)drawingBox 305 | { 306 | CGRect finalBox = CGRectZero; 307 | for (id operation in self.session.operations) { 308 | CGRect result = [operation drawRect]; 309 | if (CGRectEqualToRect(CGRectZero, finalBox)) { 310 | finalBox = result; 311 | } 312 | finalBox = CGRectUnion(finalBox, result); 313 | } 314 | 315 | return finalBox; 316 | } 317 | 318 | @end 319 | -------------------------------------------------------------------------------- /Pod/Classes/SmoothLineView.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef SmoothLineView_h 4 | #define SmoothLineView_h 5 | 6 | #import "LVSmoothLineView.h" 7 | #import "ENDBrush.h" 8 | #import "ENDBrushShadow.h" 9 | #import "ENDDrawOperation.h" 10 | #import "ENDDrawGestureRecognizer.h" 11 | 12 | #endif /* SmoothLineView_h */ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SmoothLineView 2 | 3 | [![CI Status](http://img.shields.io/travis/Andreas Kompanez/SmoothLineView.svg?style=flat)](https://travis-ci.org/Andreas Kompanez/SmoothLineView) 4 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Version](https://img.shields.io/cocoapods/v/SmoothLineView.svg?style=flat)](http://cocoapods.org/pods/SmoothLineView) 6 | [![License](https://img.shields.io/cocoapods/l/SmoothLineView.svg?style=flat)](http://cocoapods.org/pods/SmoothLineView) 7 | [![Platform](https://img.shields.io/cocoapods/p/SmoothLineView.svg?style=flat)](http://cocoapods.org/pods/SmoothLineView) 8 | 9 | Heavely based on [levinunnink](https://github.com/levinunnink) [Smooth-Line-View](https://github.com/levinunnink/Smooth-Line-View) which offers smooth & fast line drawing for iOS. This version offers additionally [CocoaPods](https://cocoapods.org), [Carthage](https://github.com/Carthage/Carthage) and undo support. 10 | 11 | ## Usage 12 | 13 | To run the example project, clone the repo, and run `pod install` from the `Example/` directory first. 14 | 15 | ## Requirements 16 | 17 | ## Installation 18 | 19 | SmoothLineView is available through [CocoaPods](http://cocoapods.org). To install 20 | it, simply add the following line to your Podfile: 21 | 22 | ```ruby 23 | pod "SmoothLineView" 24 | ``` 25 | 26 | ## Author 27 | 28 | Levi Nunnink [levinunnink](https://github.com/levinunnink), Andreas Kompanez [@kompozer](https://twitter.com/kompozer) 29 | 30 | ## License 31 | 32 | SmoothLineView is available under the MIT license. See the LICENSE file for more info. 33 | -------------------------------------------------------------------------------- /SmoothLineView.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint SmoothLineView.podspec' to ensure this is a 3 | # valid spec and remove all comments before submitting the spec. 4 | # 5 | # Any lines starting with a # are optional, but encouraged 6 | # 7 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 8 | # 9 | 10 | Pod::Spec.new do |s| 11 | s.name = "SmoothLineView" 12 | s.version = "0.1.11" 13 | s.summary = "Smooth line drawing for iOS" 14 | s.description = <<-DESC 15 | Smooth & fast line drawing from touch inputs for UIViews using Quartz 16 | 17 | DESC 18 | s.homepage = "https://github.com/kompozer/SmoothLineView" 19 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2" 20 | s.license = 'MIT' 21 | s.authors = { "Levi Nunnink" => "https://github.com/levinunnink", "Andreas Kompanez" => "https://twitter.com/kompozer" } 22 | s.source = { :git => "https://github.com/kompozer/SmoothLineView.git", :tag => s.version.to_s } 23 | s.social_media_url = 'https://twitter.com/kompozer' 24 | 25 | s.platform = :ios, '7.0' 26 | s.requires_arc = true 27 | 28 | s.source_files = 'Pod/Classes/**/*' 29 | s.resource_bundles = { 30 | 'SmoothLineView' => ['Pod/Assets/*.png'] 31 | } 32 | 33 | # s.public_header_files = 'Pod/Classes/**/*.h' 34 | # s.frameworks = 'UIKit', 'MapKit' 35 | # s.dependency 'AFNetworking', '~> 2.3' 36 | end 37 | -------------------------------------------------------------------------------- /SmoothLineView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BA025F8B1B78DE6B00139D15 /* LVSmoothLineViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BA025F8A1B78DE6B00139D15 /* LVSmoothLineViewTests.m */; }; 11 | BA78D3851B74E49500E134A7 /* ENDDrawPathOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BA78D3841B74E49500E134A7 /* ENDDrawPathOperationTests.m */; }; 12 | F5155B3D1B30CA4300F1DA58 /* SmoothLineView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F5155B311B30CA4300F1DA58 /* SmoothLineView.framework */; }; 13 | F5155B6C1B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = F5155B631B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | F5155B6D1B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = F5155B641B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.m */; }; 15 | F5155B6E1B30D0FD00F1DA58 /* ENDDrawOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = F5155B651B30D0FD00F1DA58 /* ENDDrawOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 16 | F5155B701B30D0FD00F1DA58 /* ENDDrawSession.h in Headers */ = {isa = PBXBuildFile; fileRef = F5155B671B30D0FD00F1DA58 /* ENDDrawSession.h */; }; 17 | F5155B711B30D0FD00F1DA58 /* ENDDrawSession.m in Sources */ = {isa = PBXBuildFile; fileRef = F5155B681B30D0FD00F1DA58 /* ENDDrawSession.m */; }; 18 | F5155B721B30D0FD00F1DA58 /* LVSmoothLineView.h in Headers */ = {isa = PBXBuildFile; fileRef = F5155B691B30D0FD00F1DA58 /* LVSmoothLineView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 19 | F5155B731B30D0FD00F1DA58 /* LVSmoothLineView.m in Sources */ = {isa = PBXBuildFile; fileRef = F5155B6A1B30D0FD00F1DA58 /* LVSmoothLineView.m */; }; 20 | F5155B741B30D0FD00F1DA58 /* SmoothLineView.h in Headers */ = {isa = PBXBuildFile; fileRef = F5155B6B1B30D0FD00F1DA58 /* SmoothLineView.h */; settings = {ATTRIBUTES = (Public, ); }; }; 21 | F531FAE21B36DD4F002BC283 /* ENDBrush.h in Headers */ = {isa = PBXBuildFile; fileRef = F531FADA1B36DD4F002BC283 /* ENDBrush.h */; settings = {ATTRIBUTES = (Public, ); }; }; 22 | F531FAE31B36DD4F002BC283 /* ENDBrush.m in Sources */ = {isa = PBXBuildFile; fileRef = F531FADB1B36DD4F002BC283 /* ENDBrush.m */; }; 23 | F531FAE41B36DD4F002BC283 /* ENDBrushShadow.h in Headers */ = {isa = PBXBuildFile; fileRef = F531FADC1B36DD4F002BC283 /* ENDBrushShadow.h */; settings = {ATTRIBUTES = (Public, ); }; }; 24 | F531FAE51B36DD4F002BC283 /* ENDBrushShadow.m in Sources */ = {isa = PBXBuildFile; fileRef = F531FADD1B36DD4F002BC283 /* ENDBrushShadow.m */; }; 25 | F531FAE61B36DD4F002BC283 /* ENDDrawFillWithColorOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = F531FADE1B36DD4F002BC283 /* ENDDrawFillWithColorOperation.h */; }; 26 | F531FAE71B36DD4F002BC283 /* ENDDrawFillWithColorOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F531FADF1B36DD4F002BC283 /* ENDDrawFillWithColorOperation.m */; }; 27 | F531FAE81B36DD4F002BC283 /* ENDDrawPathOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = F531FAE01B36DD4F002BC283 /* ENDDrawPathOperation.h */; }; 28 | F531FAE91B36DD4F002BC283 /* ENDDrawPathOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F531FAE11B36DD4F002BC283 /* ENDDrawPathOperation.m */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | F5155B3E1B30CA4300F1DA58 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = F5155B281B30CA4300F1DA58 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = F5155B301B30CA4300F1DA58; 37 | remoteInfo = SmoothLineView; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | BA025F8A1B78DE6B00139D15 /* LVSmoothLineViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LVSmoothLineViewTests.m; sourceTree = ""; }; 43 | BA78D3841B74E49500E134A7 /* ENDDrawPathOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ENDDrawPathOperationTests.m; sourceTree = ""; }; 44 | F5155B311B30CA4300F1DA58 /* SmoothLineView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SmoothLineView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | F5155B3C1B30CA4300F1DA58 /* SmoothLineViewTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SmoothLineViewTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | F5155B421B30CA4300F1DA58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | F5155B631B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDDrawGestureRecognizer.h; path = Pod/Classes/ENDDrawGestureRecognizer.h; sourceTree = SOURCE_ROOT; }; 48 | F5155B641B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ENDDrawGestureRecognizer.m; path = Pod/Classes/ENDDrawGestureRecognizer.m; sourceTree = SOURCE_ROOT; }; 49 | F5155B651B30D0FD00F1DA58 /* ENDDrawOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDDrawOperation.h; path = Pod/Classes/ENDDrawOperation.h; sourceTree = SOURCE_ROOT; }; 50 | F5155B671B30D0FD00F1DA58 /* ENDDrawSession.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDDrawSession.h; path = Pod/Classes/ENDDrawSession.h; sourceTree = SOURCE_ROOT; }; 51 | F5155B681B30D0FD00F1DA58 /* ENDDrawSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ENDDrawSession.m; path = Pod/Classes/ENDDrawSession.m; sourceTree = SOURCE_ROOT; }; 52 | F5155B691B30D0FD00F1DA58 /* LVSmoothLineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LVSmoothLineView.h; path = Pod/Classes/LVSmoothLineView.h; sourceTree = SOURCE_ROOT; }; 53 | F5155B6A1B30D0FD00F1DA58 /* LVSmoothLineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LVSmoothLineView.m; path = Pod/Classes/LVSmoothLineView.m; sourceTree = SOURCE_ROOT; }; 54 | F5155B6B1B30D0FD00F1DA58 /* SmoothLineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmoothLineView.h; path = Pod/Classes/SmoothLineView.h; sourceTree = SOURCE_ROOT; }; 55 | F5155B751B30D11E00F1DA58 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = SOURCE_ROOT; }; 56 | F531FADA1B36DD4F002BC283 /* ENDBrush.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDBrush.h; path = Pod/Classes/ENDBrush.h; sourceTree = SOURCE_ROOT; }; 57 | F531FADB1B36DD4F002BC283 /* ENDBrush.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ENDBrush.m; path = Pod/Classes/ENDBrush.m; sourceTree = SOURCE_ROOT; }; 58 | F531FADC1B36DD4F002BC283 /* ENDBrushShadow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDBrushShadow.h; path = Pod/Classes/ENDBrushShadow.h; sourceTree = SOURCE_ROOT; }; 59 | F531FADD1B36DD4F002BC283 /* ENDBrushShadow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ENDBrushShadow.m; path = Pod/Classes/ENDBrushShadow.m; sourceTree = SOURCE_ROOT; }; 60 | F531FADE1B36DD4F002BC283 /* ENDDrawFillWithColorOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDDrawFillWithColorOperation.h; path = Pod/Classes/ENDDrawFillWithColorOperation.h; sourceTree = SOURCE_ROOT; }; 61 | F531FADF1B36DD4F002BC283 /* ENDDrawFillWithColorOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ENDDrawFillWithColorOperation.m; path = Pod/Classes/ENDDrawFillWithColorOperation.m; sourceTree = SOURCE_ROOT; }; 62 | F531FAE01B36DD4F002BC283 /* ENDDrawPathOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ENDDrawPathOperation.h; path = Pod/Classes/ENDDrawPathOperation.h; sourceTree = SOURCE_ROOT; }; 63 | F531FAE11B36DD4F002BC283 /* ENDDrawPathOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ENDDrawPathOperation.m; path = Pod/Classes/ENDDrawPathOperation.m; sourceTree = SOURCE_ROOT; }; 64 | /* End PBXFileReference section */ 65 | 66 | /* Begin PBXFrameworksBuildPhase section */ 67 | F5155B2D1B30CA4300F1DA58 /* Frameworks */ = { 68 | isa = PBXFrameworksBuildPhase; 69 | buildActionMask = 2147483647; 70 | files = ( 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | F5155B391B30CA4300F1DA58 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | F5155B3D1B30CA4300F1DA58 /* SmoothLineView.framework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXFrameworksBuildPhase section */ 83 | 84 | /* Begin PBXGroup section */ 85 | F5155B271B30CA4300F1DA58 = { 86 | isa = PBXGroup; 87 | children = ( 88 | F5155B331B30CA4300F1DA58 /* SmoothLineView */, 89 | F5155B401B30CA4300F1DA58 /* SmoothLineViewTests */, 90 | F5155B321B30CA4300F1DA58 /* Products */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | F5155B321B30CA4300F1DA58 /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | F5155B311B30CA4300F1DA58 /* SmoothLineView.framework */, 98 | F5155B3C1B30CA4300F1DA58 /* SmoothLineViewTests.xctest */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | F5155B331B30CA4300F1DA58 /* SmoothLineView */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | F531FADA1B36DD4F002BC283 /* ENDBrush.h */, 107 | F531FADB1B36DD4F002BC283 /* ENDBrush.m */, 108 | F531FADC1B36DD4F002BC283 /* ENDBrushShadow.h */, 109 | F531FADD1B36DD4F002BC283 /* ENDBrushShadow.m */, 110 | F5155B651B30D0FD00F1DA58 /* ENDDrawOperation.h */, 111 | F531FADE1B36DD4F002BC283 /* ENDDrawFillWithColorOperation.h */, 112 | F531FADF1B36DD4F002BC283 /* ENDDrawFillWithColorOperation.m */, 113 | F531FAE01B36DD4F002BC283 /* ENDDrawPathOperation.h */, 114 | F531FAE11B36DD4F002BC283 /* ENDDrawPathOperation.m */, 115 | F5155B631B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.h */, 116 | F5155B641B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.m */, 117 | F5155B671B30D0FD00F1DA58 /* ENDDrawSession.h */, 118 | F5155B681B30D0FD00F1DA58 /* ENDDrawSession.m */, 119 | F5155B691B30D0FD00F1DA58 /* LVSmoothLineView.h */, 120 | F5155B6A1B30D0FD00F1DA58 /* LVSmoothLineView.m */, 121 | F5155B6B1B30D0FD00F1DA58 /* SmoothLineView.h */, 122 | F5155B341B30CA4300F1DA58 /* Supporting Files */, 123 | ); 124 | path = SmoothLineView; 125 | sourceTree = ""; 126 | }; 127 | F5155B341B30CA4300F1DA58 /* Supporting Files */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | F5155B751B30D11E00F1DA58 /* Info.plist */, 131 | ); 132 | name = "Supporting Files"; 133 | sourceTree = ""; 134 | }; 135 | F5155B401B30CA4300F1DA58 /* SmoothLineViewTests */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | BA78D3841B74E49500E134A7 /* ENDDrawPathOperationTests.m */, 139 | BA025F8A1B78DE6B00139D15 /* LVSmoothLineViewTests.m */, 140 | F5155B411B30CA4300F1DA58 /* Supporting Files */, 141 | ); 142 | path = SmoothLineViewTests; 143 | sourceTree = ""; 144 | }; 145 | F5155B411B30CA4300F1DA58 /* Supporting Files */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | F5155B421B30CA4300F1DA58 /* Info.plist */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | /* End PBXGroup section */ 154 | 155 | /* Begin PBXHeadersBuildPhase section */ 156 | F5155B2E1B30CA4300F1DA58 /* Headers */ = { 157 | isa = PBXHeadersBuildPhase; 158 | buildActionMask = 2147483647; 159 | files = ( 160 | F5155B741B30D0FD00F1DA58 /* SmoothLineView.h in Headers */, 161 | F5155B6E1B30D0FD00F1DA58 /* ENDDrawOperation.h in Headers */, 162 | F531FAE41B36DD4F002BC283 /* ENDBrushShadow.h in Headers */, 163 | F5155B6C1B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.h in Headers */, 164 | F531FAE21B36DD4F002BC283 /* ENDBrush.h in Headers */, 165 | F5155B721B30D0FD00F1DA58 /* LVSmoothLineView.h in Headers */, 166 | F531FAE81B36DD4F002BC283 /* ENDDrawPathOperation.h in Headers */, 167 | F531FAE61B36DD4F002BC283 /* ENDDrawFillWithColorOperation.h in Headers */, 168 | F5155B701B30D0FD00F1DA58 /* ENDDrawSession.h in Headers */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXHeadersBuildPhase section */ 173 | 174 | /* Begin PBXNativeTarget section */ 175 | F5155B301B30CA4300F1DA58 /* SmoothLineView */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = F5155B471B30CA4300F1DA58 /* Build configuration list for PBXNativeTarget "SmoothLineView" */; 178 | buildPhases = ( 179 | F5155B2C1B30CA4300F1DA58 /* Sources */, 180 | F5155B2D1B30CA4300F1DA58 /* Frameworks */, 181 | F5155B2E1B30CA4300F1DA58 /* Headers */, 182 | F5155B2F1B30CA4300F1DA58 /* Resources */, 183 | F5C58E231B3138250086CA8A /* Copy Artifacts */, 184 | ); 185 | buildRules = ( 186 | ); 187 | dependencies = ( 188 | ); 189 | name = SmoothLineView; 190 | productName = SmoothLineView; 191 | productReference = F5155B311B30CA4300F1DA58 /* SmoothLineView.framework */; 192 | productType = "com.apple.product-type.framework"; 193 | }; 194 | F5155B3B1B30CA4300F1DA58 /* SmoothLineViewTests */ = { 195 | isa = PBXNativeTarget; 196 | buildConfigurationList = F5155B4A1B30CA4300F1DA58 /* Build configuration list for PBXNativeTarget "SmoothLineViewTests" */; 197 | buildPhases = ( 198 | F5155B381B30CA4300F1DA58 /* Sources */, 199 | F5155B391B30CA4300F1DA58 /* Frameworks */, 200 | F5155B3A1B30CA4300F1DA58 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | F5155B3F1B30CA4300F1DA58 /* PBXTargetDependency */, 206 | ); 207 | name = SmoothLineViewTests; 208 | productName = SmoothLineViewTests; 209 | productReference = F5155B3C1B30CA4300F1DA58 /* SmoothLineViewTests.xctest */; 210 | productType = "com.apple.product-type.bundle.unit-test"; 211 | }; 212 | /* End PBXNativeTarget section */ 213 | 214 | /* Begin PBXProject section */ 215 | F5155B281B30CA4300F1DA58 /* Project object */ = { 216 | isa = PBXProject; 217 | attributes = { 218 | LastUpgradeCheck = 0630; 219 | ORGANIZATIONNAME = "Andreas Kompanez"; 220 | TargetAttributes = { 221 | F5155B301B30CA4300F1DA58 = { 222 | CreatedOnToolsVersion = 6.3.2; 223 | }; 224 | F5155B3B1B30CA4300F1DA58 = { 225 | CreatedOnToolsVersion = 6.3.2; 226 | }; 227 | }; 228 | }; 229 | buildConfigurationList = F5155B2B1B30CA4300F1DA58 /* Build configuration list for PBXProject "SmoothLineView" */; 230 | compatibilityVersion = "Xcode 3.2"; 231 | developmentRegion = English; 232 | hasScannedForEncodings = 0; 233 | knownRegions = ( 234 | en, 235 | ); 236 | mainGroup = F5155B271B30CA4300F1DA58; 237 | productRefGroup = F5155B321B30CA4300F1DA58 /* Products */; 238 | projectDirPath = ""; 239 | projectRoot = ""; 240 | targets = ( 241 | F5155B301B30CA4300F1DA58 /* SmoothLineView */, 242 | F5155B3B1B30CA4300F1DA58 /* SmoothLineViewTests */, 243 | ); 244 | }; 245 | /* End PBXProject section */ 246 | 247 | /* Begin PBXResourcesBuildPhase section */ 248 | F5155B2F1B30CA4300F1DA58 /* Resources */ = { 249 | isa = PBXResourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | F5155B3A1B30CA4300F1DA58 /* Resources */ = { 256 | isa = PBXResourcesBuildPhase; 257 | buildActionMask = 2147483647; 258 | files = ( 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | /* End PBXResourcesBuildPhase section */ 263 | 264 | /* Begin PBXShellScriptBuildPhase section */ 265 | F5C58E231B3138250086CA8A /* Copy Artifacts */ = { 266 | isa = PBXShellScriptBuildPhase; 267 | buildActionMask = 2147483647; 268 | files = ( 269 | ); 270 | inputPaths = ( 271 | ); 272 | name = "Copy Artifacts"; 273 | outputPaths = ( 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | shellPath = /bin/sh; 277 | shellScript = "ARTIFACTS=\"Artifacts\"\nBASE_DIR=$SRCROOT/$ARTIFACTS\nif [ -d \"${BASE_DIR}\" ];\nthen\n rm -rf $BASE_DIR\nfi\nmkdir -p $BASE_DIR\ncp -R $DWARF_DSYM_FOLDER_PATH/* $BASE_DIR"; 278 | }; 279 | /* End PBXShellScriptBuildPhase section */ 280 | 281 | /* Begin PBXSourcesBuildPhase section */ 282 | F5155B2C1B30CA4300F1DA58 /* Sources */ = { 283 | isa = PBXSourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | F531FAE91B36DD4F002BC283 /* ENDDrawPathOperation.m in Sources */, 287 | F531FAE31B36DD4F002BC283 /* ENDBrush.m in Sources */, 288 | F5155B731B30D0FD00F1DA58 /* LVSmoothLineView.m in Sources */, 289 | F531FAE71B36DD4F002BC283 /* ENDDrawFillWithColorOperation.m in Sources */, 290 | F5155B6D1B30D0FD00F1DA58 /* ENDDrawGestureRecognizer.m in Sources */, 291 | F531FAE51B36DD4F002BC283 /* ENDBrushShadow.m in Sources */, 292 | F5155B711B30D0FD00F1DA58 /* ENDDrawSession.m in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | F5155B381B30CA4300F1DA58 /* Sources */ = { 297 | isa = PBXSourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | BA025F8B1B78DE6B00139D15 /* LVSmoothLineViewTests.m in Sources */, 301 | BA78D3851B74E49500E134A7 /* ENDDrawPathOperationTests.m in Sources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | /* End PBXSourcesBuildPhase section */ 306 | 307 | /* Begin PBXTargetDependency section */ 308 | F5155B3F1B30CA4300F1DA58 /* PBXTargetDependency */ = { 309 | isa = PBXTargetDependency; 310 | target = F5155B301B30CA4300F1DA58 /* SmoothLineView */; 311 | targetProxy = F5155B3E1B30CA4300F1DA58 /* PBXContainerItemProxy */; 312 | }; 313 | /* End PBXTargetDependency section */ 314 | 315 | /* Begin XCBuildConfiguration section */ 316 | F5155B451B30CA4300F1DA58 /* Debug */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ALWAYS_SEARCH_USER_PATHS = NO; 320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 321 | CLANG_CXX_LIBRARY = "libc++"; 322 | CLANG_ENABLE_MODULES = YES; 323 | CLANG_ENABLE_OBJC_ARC = YES; 324 | CLANG_WARN_BOOL_CONVERSION = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 327 | CLANG_WARN_EMPTY_BODY = YES; 328 | CLANG_WARN_ENUM_CONVERSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 334 | COPY_PHASE_STRIP = NO; 335 | CURRENT_PROJECT_VERSION = 1; 336 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 337 | ENABLE_STRICT_OBJC_MSGSEND = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu99; 339 | GCC_DYNAMIC_NO_PIC = NO; 340 | GCC_NO_COMMON_BLOCKS = YES; 341 | GCC_OPTIMIZATION_LEVEL = 0; 342 | GCC_PREPROCESSOR_DEFINITIONS = ( 343 | "DEBUG=1", 344 | "$(inherited)", 345 | ); 346 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 347 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 348 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 349 | GCC_WARN_UNDECLARED_SELECTOR = YES; 350 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 351 | GCC_WARN_UNUSED_FUNCTION = YES; 352 | GCC_WARN_UNUSED_VARIABLE = YES; 353 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 354 | MTL_ENABLE_DEBUG_INFO = YES; 355 | ONLY_ACTIVE_ARCH = YES; 356 | SDKROOT = iphoneos; 357 | TARGETED_DEVICE_FAMILY = "1,2"; 358 | VERSIONING_SYSTEM = "apple-generic"; 359 | VERSION_INFO_PREFIX = ""; 360 | }; 361 | name = Debug; 362 | }; 363 | F5155B461B30CA4300F1DA58 /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ALWAYS_SEARCH_USER_PATHS = NO; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_EMPTY_BODY = YES; 375 | CLANG_WARN_ENUM_CONVERSION = YES; 376 | CLANG_WARN_INT_CONVERSION = YES; 377 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 378 | CLANG_WARN_UNREACHABLE_CODE = YES; 379 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 380 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 381 | COPY_PHASE_STRIP = NO; 382 | CURRENT_PROJECT_VERSION = 1; 383 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 384 | ENABLE_NS_ASSERTIONS = NO; 385 | ENABLE_STRICT_OBJC_MSGSEND = YES; 386 | GCC_C_LANGUAGE_STANDARD = gnu99; 387 | GCC_NO_COMMON_BLOCKS = YES; 388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 390 | GCC_WARN_UNDECLARED_SELECTOR = YES; 391 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 392 | GCC_WARN_UNUSED_FUNCTION = YES; 393 | GCC_WARN_UNUSED_VARIABLE = YES; 394 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 395 | MTL_ENABLE_DEBUG_INFO = NO; 396 | SDKROOT = iphoneos; 397 | TARGETED_DEVICE_FAMILY = "1,2"; 398 | VALIDATE_PRODUCT = YES; 399 | VERSIONING_SYSTEM = "apple-generic"; 400 | VERSION_INFO_PREFIX = ""; 401 | }; 402 | name = Release; 403 | }; 404 | F5155B481B30CA4300F1DA58 /* Debug */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | DEFINES_MODULE = YES; 408 | DYLIB_COMPATIBILITY_VERSION = 1; 409 | DYLIB_CURRENT_VERSION = 1; 410 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 411 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 412 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 413 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | SKIP_INSTALL = YES; 416 | }; 417 | name = Debug; 418 | }; 419 | F5155B491B30CA4300F1DA58 /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | DEFINES_MODULE = YES; 423 | DYLIB_COMPATIBILITY_VERSION = 1; 424 | DYLIB_CURRENT_VERSION = 1; 425 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 426 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 427 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 428 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 429 | PRODUCT_NAME = "$(TARGET_NAME)"; 430 | SKIP_INSTALL = YES; 431 | }; 432 | name = Release; 433 | }; 434 | F5155B4B1B30CA4300F1DA58 /* Debug */ = { 435 | isa = XCBuildConfiguration; 436 | buildSettings = { 437 | FRAMEWORK_SEARCH_PATHS = ( 438 | "$(SDKROOT)/Developer/Library/Frameworks", 439 | "$(inherited)", 440 | ); 441 | GCC_PREPROCESSOR_DEFINITIONS = ( 442 | "DEBUG=1", 443 | "$(inherited)", 444 | ); 445 | INFOPLIST_FILE = SmoothLineViewTests/Info.plist; 446 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 447 | PRODUCT_NAME = "$(TARGET_NAME)"; 448 | }; 449 | name = Debug; 450 | }; 451 | F5155B4C1B30CA4300F1DA58 /* Release */ = { 452 | isa = XCBuildConfiguration; 453 | buildSettings = { 454 | FRAMEWORK_SEARCH_PATHS = ( 455 | "$(SDKROOT)/Developer/Library/Frameworks", 456 | "$(inherited)", 457 | ); 458 | INFOPLIST_FILE = SmoothLineViewTests/Info.plist; 459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 460 | PRODUCT_NAME = "$(TARGET_NAME)"; 461 | }; 462 | name = Release; 463 | }; 464 | /* End XCBuildConfiguration section */ 465 | 466 | /* Begin XCConfigurationList section */ 467 | F5155B2B1B30CA4300F1DA58 /* Build configuration list for PBXProject "SmoothLineView" */ = { 468 | isa = XCConfigurationList; 469 | buildConfigurations = ( 470 | F5155B451B30CA4300F1DA58 /* Debug */, 471 | F5155B461B30CA4300F1DA58 /* Release */, 472 | ); 473 | defaultConfigurationIsVisible = 0; 474 | defaultConfigurationName = Release; 475 | }; 476 | F5155B471B30CA4300F1DA58 /* Build configuration list for PBXNativeTarget "SmoothLineView" */ = { 477 | isa = XCConfigurationList; 478 | buildConfigurations = ( 479 | F5155B481B30CA4300F1DA58 /* Debug */, 480 | F5155B491B30CA4300F1DA58 /* Release */, 481 | ); 482 | defaultConfigurationIsVisible = 0; 483 | defaultConfigurationName = Release; 484 | }; 485 | F5155B4A1B30CA4300F1DA58 /* Build configuration list for PBXNativeTarget "SmoothLineViewTests" */ = { 486 | isa = XCConfigurationList; 487 | buildConfigurations = ( 488 | F5155B4B1B30CA4300F1DA58 /* Debug */, 489 | F5155B4C1B30CA4300F1DA58 /* Release */, 490 | ); 491 | defaultConfigurationIsVisible = 0; 492 | defaultConfigurationName = Release; 493 | }; 494 | /* End XCConfigurationList section */ 495 | }; 496 | rootObject = F5155B281B30CA4300F1DA58 /* Project object */; 497 | } 498 | -------------------------------------------------------------------------------- /SmoothLineView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SmoothLineView.xcodeproj/xcshareddata/xcschemes/SmoothLineView.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /SmoothLineViewTests/ENDDrawPathOperationTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ENDDrawPathOperationTests.m 3 | // SmoothLineView 4 | // 5 | // Created by Andreas Kompanez on 07.08.15. 6 | // Copyright (c) 2015 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "ENDDrawPathOperation.h" 13 | #import "ENDBrush.h" 14 | #import "ENDDrawOperation.h" 15 | 16 | 17 | 18 | @interface ENDDrawPathOperationTests : XCTestCase 19 | 20 | @property (nonatomic) ENDDrawPathOperation *operation; 21 | 22 | @end 23 | 24 | @implementation ENDDrawPathOperationTests 25 | 26 | - (void)setUp 27 | { 28 | [super setUp]; 29 | 30 | self.operation = [ENDDrawPathOperation new]; 31 | ENDBrush *brush = [ENDBrush new]; 32 | brush.lineWidth = 1; 33 | self.operation.brush = brush; 34 | } 35 | 36 | - (void)tearDown 37 | { 38 | [super tearDown]; 39 | 40 | self.operation = nil; 41 | } 42 | 43 | - (void)testThatDrawRectIsNotZero 44 | { 45 | // Reduce the brush size to get the exact draw box as the path 46 | self.operation.brush.lineWidth = 0; 47 | CGRect startRect = CGRectMake(0, 0, 100, 100); 48 | 49 | UIBezierPath *path = [UIBezierPath bezierPath]; 50 | [path moveToPoint:CGPointMake(startRect.origin.x, startRect.origin.y)]; 51 | [path addLineToPoint:CGPointMake(startRect.origin.x, CGRectGetHeight(startRect))]; 52 | [path addLineToPoint:CGPointMake(CGRectGetWidth(startRect), CGRectGetHeight(startRect))]; 53 | [path addLineToPoint:CGPointMake(startRect.origin.x, startRect.origin.y)]; 54 | [self.operation addSubpath:path]; 55 | 56 | CGRect drawRect = [self.operation drawRect]; 57 | XCTAssertFalse(CGRectEqualToRect(drawRect, CGRectZero), @"Draw rect is zero"); 58 | XCTAssertTrue(CGRectEqualToRect(drawRect, startRect), @"Start and end draw rects are different"); 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SmoothLineViewTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.endlessnumbered.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /SmoothLineViewTests/LVSmoothLineViewTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LVSmoothLineViewTests.m 3 | // SmoothLineView 4 | // 5 | // Created by Andreas Kompanez on 10.08.15. 6 | // Copyright (c) 2015 Andreas Kompanez. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #import "LVSmoothLineView.h" 13 | #import "ENDDrawOperation.h" 14 | #import "ENDDrawPathOperation.h" 15 | #import "ENDDrawFillWithColorOperation.h" 16 | #import "ENDBrush.h" 17 | #import "ENDDrawSession.h" 18 | 19 | 20 | 21 | @interface LVSmoothLineView (Internal) 22 | 23 | @property (nonatomic, strong) ENDDrawSession *session; 24 | 25 | @end 26 | 27 | @interface LVSmoothLineViewTests : XCTestCase 28 | 29 | @property (nonatomic) LVSmoothLineView *sketchView; 30 | 31 | @end 32 | 33 | @implementation LVSmoothLineViewTests 34 | 35 | - (void)setUp 36 | { 37 | [super setUp]; 38 | 39 | // Put setup code here. This method is called before the invocation of each test method in the class. 40 | 41 | self.sketchView = [[LVSmoothLineView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)]; 42 | } 43 | 44 | - (void)tearDown 45 | { 46 | // Put teardown code here. This method is called after the invocation of each test method in the class. 47 | [super tearDown]; 48 | 49 | self.sketchView = nil; 50 | } 51 | 52 | - (void)testThatDrawingBoxMethodIsCorrectWithJustDrawPathOperation 53 | { 54 | ENDDrawPathOperation *operation = [self.sketchView.session beginOperation:[ENDDrawPathOperation class]]; 55 | ENDBrush *brush = [ENDBrush new]; 56 | brush.lineWidth = 0.0; 57 | operation.brush = brush; 58 | // 100x100 rect at the 50,50 pos 59 | CGRect startRect = CGRectMake(50, 50, 150, 150); 60 | 61 | UIBezierPath *path = [UIBezierPath bezierPath]; 62 | [path moveToPoint:CGPointMake(startRect.origin.x, startRect.origin.y)]; 63 | [path addLineToPoint:CGPointMake(startRect.origin.x, CGRectGetHeight(startRect))]; 64 | [path addLineToPoint:CGPointMake(CGRectGetWidth(startRect), CGRectGetHeight(startRect))]; 65 | [path addLineToPoint:CGPointMake(startRect.origin.x, startRect.origin.y)]; 66 | [path closePath]; 67 | [operation addSubpath:path]; 68 | 69 | [self.sketchView.session endOperation]; 70 | 71 | CGRect drawingBox = [self.sketchView drawingBox]; 72 | XCTAssertFalse(CGRectEqualToRect(drawingBox, CGRectZero)); 73 | XCTAssertTrue(CGRectEqualToRect(drawingBox, CGRectMake(50, 50, 100, 100))); 74 | } 75 | 76 | - (void)testThatDrawingBoxMethodIsCorrectWithPathAndFillOperations 77 | { 78 | // Path 79 | ENDDrawPathOperation *operation = [self.sketchView.session beginOperation:[ENDDrawPathOperation class]]; 80 | ENDBrush *brush = [ENDBrush new]; 81 | brush.lineWidth = 0.0; 82 | operation.brush = brush; 83 | // 100x100 rect at the 50,50 pos 84 | CGRect startRect = CGRectMake(50, 50, 150, 150); 85 | 86 | UIBezierPath *path = [UIBezierPath bezierPath]; 87 | [path moveToPoint:CGPointMake(startRect.origin.x, startRect.origin.y)]; 88 | [path addLineToPoint:CGPointMake(startRect.origin.x, CGRectGetHeight(startRect))]; 89 | [path addLineToPoint:CGPointMake(CGRectGetWidth(startRect), CGRectGetHeight(startRect))]; 90 | [path addLineToPoint:CGPointMake(startRect.origin.x, startRect.origin.y)]; 91 | [path closePath]; 92 | [operation addSubpath:path]; 93 | [self.sketchView.session endOperation]; 94 | 95 | // Fill 96 | ENDDrawFillWithColorOperation *fillOperation = [self.sketchView.session beginOperation:[ENDDrawFillWithColorOperation class]]; 97 | fillOperation.fillRect = self.sketchView.bounds; 98 | [self.sketchView.session endOperation]; 99 | 100 | 101 | CGRect drawingBox = [self.sketchView drawingBox]; 102 | XCTAssertFalse(CGRectEqualToRect(drawingBox, CGRectZero)); 103 | XCTAssertTrue(CGRectEqualToRect(drawingBox, self.sketchView.bounds)); 104 | } 105 | 106 | @end 107 | --------------------------------------------------------------------------------