├── .DS_Store ├── .gitignore ├── README.md └── WSLineChart ├── .DS_Store ├── WSLineChart.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── WSLineChart ├── .DS_Store ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m ├── WSLineChartView ├── .DS_Store ├── SVProgressHUD │ ├── .DS_Store │ ├── SVProgressHUD.bundle │ │ ├── error-black.png │ │ ├── error-black@2x.png │ │ ├── error.png │ │ ├── error@2x.png │ │ ├── success-black.png │ │ ├── success-black@2x.png │ │ ├── success.png │ │ └── success@2x.png │ ├── SVProgressHUD.h │ ├── SVProgressHUD.m │ ├── TBActivityView.h │ └── TBActivityView.m ├── WSLineChartView.h ├── WSLineChartView.m ├── XAxisView.h ├── XAxisView.m ├── YAxisView.h └── YAxisView.m └── main.m /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WSLineChartView 2 | 折线图,支持放大缩小,横向定位放大,增加长按功能,y轴的值可以自己设置。采用贝塞尔曲线,核心绘图,左右滑动流畅 3 | 4 | 5 | # PhotoShoot 6 | 7 | ![image](https://img-blog.csdnimg.cn/20191218154840257.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI2NTk4MDc3,size_16,color_FFFFFF,t_70) 8 | 9 | ![image](https://img-blog.csdnimg.cn/20191218154911428.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI2NTk4MDc3,size_16,color_FFFFFF,t_70) 10 | 11 | # How To Use 12 | 13 | ```ruby 14 | 15 | 1.将WSLineChartView文件夹拖入工程中 16 | 17 | #import "WSLineChartView.h" 18 | 19 | NSMutableArray *xArray = [NSMutableArray array]; 20 | NSMutableArray *yArray = [NSMutableArray array]; 21 | for (NSInteger i = 0; i < 100; i++) { 22 | 23 | [xArray addObject:[NSString stringWithFormat:@"%ld",i]]; 24 | [yArray addObject:[NSString stringWithFormat:@"%.2lf",20.0+arc4random_uniform(10)]]; 25 | 26 | } 27 | 28 | //这里你可以计算出yArray的最大最小值。设置为曲线的最大最小值,这样画出来的线占据整个y轴高度。 29 | //.......... 30 | 31 | WSLineChartView *wsLine = [[WSLineChartView alloc]initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height-200) xTitleArray:xArray yValueArray:yArray yMax:40 yMin:10 yTypeName:@"高考成绩" xTypeName:@"考生号" unit:@"分"]; 32 | [self.view addSubview:wsLine]; 33 | 34 | 喜欢的点个星。 (*^__^*) 35 | 36 | ``` 37 | -------------------------------------------------------------------------------- /WSLineChart/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/.DS_Store -------------------------------------------------------------------------------- /WSLineChart/WSLineChart.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8882023D1DDD892B005AF441 /* WSLineChartView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8882023C1DDD892B005AF441 /* WSLineChartView.m */; }; 11 | 888202401DDD8A2B005AF441 /* XAxisView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8882023F1DDD8A2B005AF441 /* XAxisView.m */; }; 12 | 888202431DDD8A33005AF441 /* YAxisView.m in Sources */ = {isa = PBXBuildFile; fileRef = 888202421DDD8A33005AF441 /* YAxisView.m */; }; 13 | 8882024A1DDD91D1005AF441 /* SVProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 888202451DDD91D1005AF441 /* SVProgressHUD.bundle */; }; 14 | 8882024B1DDD91D1005AF441 /* SVProgressHUD.m in Sources */ = {isa = PBXBuildFile; fileRef = 888202471DDD91D1005AF441 /* SVProgressHUD.m */; }; 15 | 8882024C1DDD91D1005AF441 /* TBActivityView.m in Sources */ = {isa = PBXBuildFile; fileRef = 888202491DDD91D1005AF441 /* TBActivityView.m */; }; 16 | 889097621DD9EAC700F2DEAF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 889097611DD9EAC700F2DEAF /* main.m */; }; 17 | 889097651DD9EAC700F2DEAF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 889097641DD9EAC700F2DEAF /* AppDelegate.m */; }; 18 | 889097681DD9EAC700F2DEAF /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 889097671DD9EAC700F2DEAF /* ViewController.m */; }; 19 | 8890976B1DD9EAC700F2DEAF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 889097691DD9EAC700F2DEAF /* Main.storyboard */; }; 20 | 8890976D1DD9EAC700F2DEAF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8890976C1DD9EAC700F2DEAF /* Assets.xcassets */; }; 21 | 889097701DD9EAC700F2DEAF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8890976E1DD9EAC700F2DEAF /* LaunchScreen.storyboard */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | 8882023B1DDD892B005AF441 /* WSLineChartView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WSLineChartView.h; sourceTree = ""; }; 26 | 8882023C1DDD892B005AF441 /* WSLineChartView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WSLineChartView.m; sourceTree = ""; }; 27 | 8882023E1DDD8A2B005AF441 /* XAxisView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XAxisView.h; sourceTree = ""; }; 28 | 8882023F1DDD8A2B005AF441 /* XAxisView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XAxisView.m; sourceTree = ""; }; 29 | 888202411DDD8A33005AF441 /* YAxisView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YAxisView.h; sourceTree = ""; }; 30 | 888202421DDD8A33005AF441 /* YAxisView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YAxisView.m; sourceTree = ""; }; 31 | 888202451DDD91D1005AF441 /* SVProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = SVProgressHUD.bundle; sourceTree = ""; }; 32 | 888202461DDD91D1005AF441 /* SVProgressHUD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVProgressHUD.h; sourceTree = ""; }; 33 | 888202471DDD91D1005AF441 /* SVProgressHUD.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SVProgressHUD.m; sourceTree = ""; }; 34 | 888202481DDD91D1005AF441 /* TBActivityView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TBActivityView.h; sourceTree = ""; }; 35 | 888202491DDD91D1005AF441 /* TBActivityView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TBActivityView.m; sourceTree = ""; }; 36 | 8890975D1DD9EAC700F2DEAF /* WSLineChart.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WSLineChart.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 889097611DD9EAC700F2DEAF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 38 | 889097631DD9EAC700F2DEAF /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | 889097641DD9EAC700F2DEAF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | 889097661DD9EAC700F2DEAF /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 41 | 889097671DD9EAC700F2DEAF /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 42 | 8890976A1DD9EAC700F2DEAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 43 | 8890976C1DD9EAC700F2DEAF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 44 | 8890976F1DD9EAC700F2DEAF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 45 | 889097711DD9EAC700F2DEAF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | 8890975A1DD9EAC700F2DEAF /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | 888202371DDD88C9005AF441 /* WSLineChartView */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 888202441DDD91D1005AF441 /* SVProgressHUD */, 63 | 8882023B1DDD892B005AF441 /* WSLineChartView.h */, 64 | 8882023C1DDD892B005AF441 /* WSLineChartView.m */, 65 | 8882023E1DDD8A2B005AF441 /* XAxisView.h */, 66 | 8882023F1DDD8A2B005AF441 /* XAxisView.m */, 67 | 888202411DDD8A33005AF441 /* YAxisView.h */, 68 | 888202421DDD8A33005AF441 /* YAxisView.m */, 69 | ); 70 | path = WSLineChartView; 71 | sourceTree = ""; 72 | }; 73 | 888202441DDD91D1005AF441 /* SVProgressHUD */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 888202451DDD91D1005AF441 /* SVProgressHUD.bundle */, 77 | 888202461DDD91D1005AF441 /* SVProgressHUD.h */, 78 | 888202471DDD91D1005AF441 /* SVProgressHUD.m */, 79 | 888202481DDD91D1005AF441 /* TBActivityView.h */, 80 | 888202491DDD91D1005AF441 /* TBActivityView.m */, 81 | ); 82 | path = SVProgressHUD; 83 | sourceTree = ""; 84 | }; 85 | 889097541DD9EAC700F2DEAF = { 86 | isa = PBXGroup; 87 | children = ( 88 | 8890975F1DD9EAC700F2DEAF /* WSLineChart */, 89 | 8890975E1DD9EAC700F2DEAF /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | 8890975E1DD9EAC700F2DEAF /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 8890975D1DD9EAC700F2DEAF /* WSLineChart.app */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | 8890975F1DD9EAC700F2DEAF /* WSLineChart */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 889097631DD9EAC700F2DEAF /* AppDelegate.h */, 105 | 889097641DD9EAC700F2DEAF /* AppDelegate.m */, 106 | 889097661DD9EAC700F2DEAF /* ViewController.h */, 107 | 889097671DD9EAC700F2DEAF /* ViewController.m */, 108 | 888202371DDD88C9005AF441 /* WSLineChartView */, 109 | 889097691DD9EAC700F2DEAF /* Main.storyboard */, 110 | 8890976C1DD9EAC700F2DEAF /* Assets.xcassets */, 111 | 8890976E1DD9EAC700F2DEAF /* LaunchScreen.storyboard */, 112 | 889097711DD9EAC700F2DEAF /* Info.plist */, 113 | 889097601DD9EAC700F2DEAF /* Supporting Files */, 114 | ); 115 | path = WSLineChart; 116 | sourceTree = ""; 117 | }; 118 | 889097601DD9EAC700F2DEAF /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 889097611DD9EAC700F2DEAF /* main.m */, 122 | ); 123 | name = "Supporting Files"; 124 | sourceTree = ""; 125 | }; 126 | /* End PBXGroup section */ 127 | 128 | /* Begin PBXNativeTarget section */ 129 | 8890975C1DD9EAC700F2DEAF /* WSLineChart */ = { 130 | isa = PBXNativeTarget; 131 | buildConfigurationList = 889097741DD9EAC700F2DEAF /* Build configuration list for PBXNativeTarget "WSLineChart" */; 132 | buildPhases = ( 133 | 889097591DD9EAC700F2DEAF /* Sources */, 134 | 8890975A1DD9EAC700F2DEAF /* Frameworks */, 135 | 8890975B1DD9EAC700F2DEAF /* Resources */, 136 | ); 137 | buildRules = ( 138 | ); 139 | dependencies = ( 140 | ); 141 | name = WSLineChart; 142 | productName = WSLineChart; 143 | productReference = 8890975D1DD9EAC700F2DEAF /* WSLineChart.app */; 144 | productType = "com.apple.product-type.application"; 145 | }; 146 | /* End PBXNativeTarget section */ 147 | 148 | /* Begin PBXProject section */ 149 | 889097551DD9EAC700F2DEAF /* Project object */ = { 150 | isa = PBXProject; 151 | attributes = { 152 | LastUpgradeCheck = 0730; 153 | ORGANIZATIONNAME = zws; 154 | TargetAttributes = { 155 | 8890975C1DD9EAC700F2DEAF = { 156 | CreatedOnToolsVersion = 7.3.1; 157 | }; 158 | }; 159 | }; 160 | buildConfigurationList = 889097581DD9EAC700F2DEAF /* Build configuration list for PBXProject "WSLineChart" */; 161 | compatibilityVersion = "Xcode 3.2"; 162 | developmentRegion = English; 163 | hasScannedForEncodings = 0; 164 | knownRegions = ( 165 | en, 166 | Base, 167 | ); 168 | mainGroup = 889097541DD9EAC700F2DEAF; 169 | productRefGroup = 8890975E1DD9EAC700F2DEAF /* Products */; 170 | projectDirPath = ""; 171 | projectRoot = ""; 172 | targets = ( 173 | 8890975C1DD9EAC700F2DEAF /* WSLineChart */, 174 | ); 175 | }; 176 | /* End PBXProject section */ 177 | 178 | /* Begin PBXResourcesBuildPhase section */ 179 | 8890975B1DD9EAC700F2DEAF /* Resources */ = { 180 | isa = PBXResourcesBuildPhase; 181 | buildActionMask = 2147483647; 182 | files = ( 183 | 889097701DD9EAC700F2DEAF /* LaunchScreen.storyboard in Resources */, 184 | 8890976D1DD9EAC700F2DEAF /* Assets.xcassets in Resources */, 185 | 8890976B1DD9EAC700F2DEAF /* Main.storyboard in Resources */, 186 | 8882024A1DDD91D1005AF441 /* SVProgressHUD.bundle in Resources */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXResourcesBuildPhase section */ 191 | 192 | /* Begin PBXSourcesBuildPhase section */ 193 | 889097591DD9EAC700F2DEAF /* Sources */ = { 194 | isa = PBXSourcesBuildPhase; 195 | buildActionMask = 2147483647; 196 | files = ( 197 | 889097681DD9EAC700F2DEAF /* ViewController.m in Sources */, 198 | 8882024C1DDD91D1005AF441 /* TBActivityView.m in Sources */, 199 | 888202431DDD8A33005AF441 /* YAxisView.m in Sources */, 200 | 889097651DD9EAC700F2DEAF /* AppDelegate.m in Sources */, 201 | 8882024B1DDD91D1005AF441 /* SVProgressHUD.m in Sources */, 202 | 889097621DD9EAC700F2DEAF /* main.m in Sources */, 203 | 888202401DDD8A2B005AF441 /* XAxisView.m in Sources */, 204 | 8882023D1DDD892B005AF441 /* WSLineChartView.m in Sources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXSourcesBuildPhase section */ 209 | 210 | /* Begin PBXVariantGroup section */ 211 | 889097691DD9EAC700F2DEAF /* Main.storyboard */ = { 212 | isa = PBXVariantGroup; 213 | children = ( 214 | 8890976A1DD9EAC700F2DEAF /* Base */, 215 | ); 216 | name = Main.storyboard; 217 | sourceTree = ""; 218 | }; 219 | 8890976E1DD9EAC700F2DEAF /* LaunchScreen.storyboard */ = { 220 | isa = PBXVariantGroup; 221 | children = ( 222 | 8890976F1DD9EAC700F2DEAF /* Base */, 223 | ); 224 | name = LaunchScreen.storyboard; 225 | sourceTree = ""; 226 | }; 227 | /* End PBXVariantGroup section */ 228 | 229 | /* Begin XCBuildConfiguration section */ 230 | 889097721DD9EAC700F2DEAF /* Debug */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | ALWAYS_SEARCH_USER_PATHS = NO; 234 | CLANG_ANALYZER_NONNULL = YES; 235 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 236 | CLANG_CXX_LIBRARY = "libc++"; 237 | CLANG_ENABLE_MODULES = YES; 238 | CLANG_ENABLE_OBJC_ARC = YES; 239 | CLANG_WARN_BOOL_CONVERSION = YES; 240 | CLANG_WARN_CONSTANT_CONVERSION = YES; 241 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 242 | CLANG_WARN_EMPTY_BODY = YES; 243 | CLANG_WARN_ENUM_CONVERSION = YES; 244 | CLANG_WARN_INT_CONVERSION = YES; 245 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 246 | CLANG_WARN_UNREACHABLE_CODE = YES; 247 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 248 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 249 | COPY_PHASE_STRIP = NO; 250 | DEBUG_INFORMATION_FORMAT = dwarf; 251 | ENABLE_STRICT_OBJC_MSGSEND = YES; 252 | ENABLE_TESTABILITY = YES; 253 | GCC_C_LANGUAGE_STANDARD = gnu99; 254 | GCC_DYNAMIC_NO_PIC = NO; 255 | GCC_NO_COMMON_BLOCKS = YES; 256 | GCC_OPTIMIZATION_LEVEL = 0; 257 | GCC_PREPROCESSOR_DEFINITIONS = ( 258 | "DEBUG=1", 259 | "$(inherited)", 260 | ); 261 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 262 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 263 | GCC_WARN_UNDECLARED_SELECTOR = YES; 264 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 265 | GCC_WARN_UNUSED_FUNCTION = YES; 266 | GCC_WARN_UNUSED_VARIABLE = YES; 267 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 268 | MTL_ENABLE_DEBUG_INFO = YES; 269 | ONLY_ACTIVE_ARCH = YES; 270 | SDKROOT = iphoneos; 271 | }; 272 | name = Debug; 273 | }; 274 | 889097731DD9EAC700F2DEAF /* Release */ = { 275 | isa = XCBuildConfiguration; 276 | buildSettings = { 277 | ALWAYS_SEARCH_USER_PATHS = NO; 278 | CLANG_ANALYZER_NONNULL = YES; 279 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 280 | CLANG_CXX_LIBRARY = "libc++"; 281 | CLANG_ENABLE_MODULES = YES; 282 | CLANG_ENABLE_OBJC_ARC = YES; 283 | CLANG_WARN_BOOL_CONVERSION = YES; 284 | CLANG_WARN_CONSTANT_CONVERSION = YES; 285 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN_ENUM_CONVERSION = YES; 288 | CLANG_WARN_INT_CONVERSION = YES; 289 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 290 | CLANG_WARN_UNREACHABLE_CODE = YES; 291 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 292 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 293 | COPY_PHASE_STRIP = NO; 294 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 295 | ENABLE_NS_ASSERTIONS = NO; 296 | ENABLE_STRICT_OBJC_MSGSEND = YES; 297 | GCC_C_LANGUAGE_STANDARD = gnu99; 298 | GCC_NO_COMMON_BLOCKS = YES; 299 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 300 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 301 | GCC_WARN_UNDECLARED_SELECTOR = YES; 302 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 303 | GCC_WARN_UNUSED_FUNCTION = YES; 304 | GCC_WARN_UNUSED_VARIABLE = YES; 305 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 306 | MTL_ENABLE_DEBUG_INFO = NO; 307 | SDKROOT = iphoneos; 308 | VALIDATE_PRODUCT = YES; 309 | }; 310 | name = Release; 311 | }; 312 | 889097751DD9EAC700F2DEAF /* Debug */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 316 | INFOPLIST_FILE = WSLineChart/Info.plist; 317 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 319 | PRODUCT_BUNDLE_IDENTIFIER = com.sinfotek.WSLineChart; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | }; 322 | name = Debug; 323 | }; 324 | 889097761DD9EAC700F2DEAF /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 328 | INFOPLIST_FILE = WSLineChart/Info.plist; 329 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 330 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 331 | PRODUCT_BUNDLE_IDENTIFIER = com.sinfotek.WSLineChart; 332 | PRODUCT_NAME = "$(TARGET_NAME)"; 333 | }; 334 | name = Release; 335 | }; 336 | /* End XCBuildConfiguration section */ 337 | 338 | /* Begin XCConfigurationList section */ 339 | 889097581DD9EAC700F2DEAF /* Build configuration list for PBXProject "WSLineChart" */ = { 340 | isa = XCConfigurationList; 341 | buildConfigurations = ( 342 | 889097721DD9EAC700F2DEAF /* Debug */, 343 | 889097731DD9EAC700F2DEAF /* Release */, 344 | ); 345 | defaultConfigurationIsVisible = 0; 346 | defaultConfigurationName = Release; 347 | }; 348 | 889097741DD9EAC700F2DEAF /* Build configuration list for PBXNativeTarget "WSLineChart" */ = { 349 | isa = XCConfigurationList; 350 | buildConfigurations = ( 351 | 889097751DD9EAC700F2DEAF /* Debug */, 352 | 889097761DD9EAC700F2DEAF /* Release */, 353 | ); 354 | defaultConfigurationIsVisible = 0; 355 | defaultConfigurationName = Release; 356 | }; 357 | /* End XCConfigurationList section */ 358 | }; 359 | rootObject = 889097551DD9EAC700F2DEAF /* Project object */; 360 | } 361 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/.DS_Store -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // WSLineChart 4 | // 5 | // Created by iMac on 16/11/14. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // WSLineChart 4 | // 5 | // Created by iMac on 16/11/14. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // 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. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 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 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/Assets.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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/Base.lproj/Main.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 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // WSLineChart 4 | // 5 | // Created by iMac on 16/11/14. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // WSLineChart 4 | // 5 | // Created by iMac on 16/11/14. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "WSLineChartView.h" 11 | 12 | 13 | @interface ViewController () 14 | 15 | @end 16 | 17 | @implementation ViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.view.backgroundColor = [UIColor whiteColor]; 22 | 23 | NSMutableArray *xArray = [NSMutableArray array]; 24 | NSMutableArray *yArray = [NSMutableArray array]; 25 | for (NSInteger i = 0; i < 100; i++) { 26 | 27 | [xArray addObject:[NSString stringWithFormat:@"%ld",i]]; 28 | [yArray addObject:[NSString stringWithFormat:@"%.2lf",20.0+arc4random_uniform(10)]]; 29 | 30 | } 31 | 32 | //这里你可以计算出yArray的最大最小值。设置为曲线的最大最小值,这样画出来的线占据整个y轴高度。 33 | //.......... 34 | 35 | WSLineChartView *wsLine = [[WSLineChartView alloc]initWithFrame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height-200) xTitleArray:xArray yValueArray:yArray yMax:40 yMin:10 yTypeName:@"高考成绩" xTypeName:@"考生号" unit:@"分"]; 36 | [self.view addSubview:wsLine]; 37 | 38 | } 39 | 40 | 41 | 42 | 43 | 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/.DS_Store -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/.DS_Store -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error-black.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error-black@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error-black@2x.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/error@2x.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success-black.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success-black@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success-black@2x.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zws-China/WSLineChartView/dd7a9adf964b6a92a331eb668588d46e3406be96/WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.bundle/success@2x.png -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // SVProgressHUD.h 3 | // 4 | // Created by Sam Vermette on 27.03.11. 5 | // Copyright 2011 Sam Vermette. All rights reserved. 6 | // 7 | // https://github.com/samvermette/SVProgressHUD 8 | // 9 | 10 | #import 11 | #import 12 | 13 | extern NSString * const SVProgressHUDDidReceiveTouchEventNotification; 14 | extern NSString * const SVProgressHUDWillDisappearNotification; 15 | extern NSString * const SVProgressHUDDidDisappearNotification; 16 | extern NSString * const SVProgressHUDWillAppearNotification; 17 | extern NSString * const SVProgressHUDDidAppearNotification; 18 | 19 | extern NSString * const SVProgressHUDStatusUserInfoKey; 20 | 21 | enum { 22 | SVProgressHUDMaskTypeNone = 1, // allow user interactions while HUD is displayed 23 | SVProgressHUDMaskTypeClear, // don't allow 24 | SVProgressHUDMaskTypeBlack, // don't allow and dim the UI in the back of the HUD 25 | SVProgressHUDMaskTypeGradient // don't allow and dim the UI with a a-la-alert-view bg gradient 26 | }; 27 | 28 | typedef NSUInteger SVProgressHUDMaskType; 29 | 30 | @interface SVProgressHUD : UIView 31 | 32 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 33 | @property (readwrite, nonatomic, retain) UIColor *hudBackgroundColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 34 | @property (readwrite, nonatomic, retain) UIColor *hudForegroundColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 35 | @property (readwrite, nonatomic, retain) UIColor *hudStatusShadowColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 36 | @property (readwrite, nonatomic, retain) UIColor *hudRingBackgroundColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 37 | @property (readwrite, nonatomic, retain) UIColor *hudRingForegroundColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 38 | @property (readwrite, nonatomic, retain) UIFont *hudFont NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 39 | @property (readwrite, nonatomic, retain) UIImage *hudSuccessImage NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 40 | @property (readwrite, nonatomic, retain) UIImage *hudErrorImage NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR; 41 | #endif 42 | 43 | + (void)setOffsetFromCenter:(UIOffset)offset; 44 | + (void)resetOffsetFromCenter; 45 | 46 | + (void)show; 47 | + (void)showWithMaskType:(SVProgressHUDMaskType)maskType; 48 | + (void)showWithStatus:(NSString*)status; 49 | + (void)showWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType; 50 | 51 | + (void)showProgress:(float)progress; 52 | + (void)showProgress:(float)progress status:(NSString*)status; 53 | + (void)showProgress:(float)progress status:(NSString*)status maskType:(SVProgressHUDMaskType)maskType; 54 | 55 | + (void)setStatus:(NSString*)string; // change the HUD loading status while it's showing 56 | 57 | // stops the activity indicator, shows a glyph + status, and dismisses HUD 1s later 58 | + (void)showSuccessWithStatus:(NSString*)string; 59 | + (void)showErrorWithStatus:(NSString *)string; 60 | + (void)showImage:(UIImage*)image status:(NSString*)status; // use 28x28 white pngs 61 | 62 | + (void)popActivity; 63 | + (void)dismiss; 64 | 65 | + (BOOL)isVisible; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/SVProgressHUD.m: -------------------------------------------------------------------------------- 1 | // 2 | // SVProgressHUD.m 3 | // 4 | // Created by Sam Vermette on 27.03.11. 5 | // Copyright 2011 Sam Vermette. All rights reserved. 6 | // 7 | // https://github.com/samvermette/SVProgressHUD 8 | // 9 | 10 | #if !__has_feature(objc_arc) 11 | #error SVProgressHUD is ARC only. Either turn on ARC for the project or use -fobjc-arc flag 12 | #endif 13 | 14 | #import "SVProgressHUD.h" 15 | #import 16 | #import "TBActivityView.h" 17 | 18 | NSString * const SVProgressHUDDidReceiveTouchEventNotification = @"SVProgressHUDDidReceiveTouchEventNotification"; 19 | NSString * const SVProgressHUDWillDisappearNotification = @"SVProgressHUDWillDisappearNotification"; 20 | NSString * const SVProgressHUDDidDisappearNotification = @"SVProgressHUDDidDisappearNotification"; 21 | NSString * const SVProgressHUDWillAppearNotification = @"SVProgressHUDWillAppearNotification"; 22 | NSString * const SVProgressHUDDidAppearNotification = @"SVProgressHUDDidAppearNotification"; 23 | 24 | NSString * const SVProgressHUDStatusUserInfoKey = @"SVProgressHUDStatusUserInfoKey"; 25 | 26 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 27 | CGFloat SVProgressHUDRingRadius = 3; 28 | CGFloat SVProgressHUDRingThickness = 1; 29 | #else 30 | CGFloat SVProgressHUDRingRadius = 3; 31 | CGFloat SVProgressHUDRingThickness = 6; 32 | #endif 33 | 34 | @interface SVProgressHUD () 35 | 36 | @property (nonatomic, readwrite) SVProgressHUDMaskType maskType; 37 | @property (nonatomic, strong, readonly) NSTimer *fadeOutTimer; 38 | @property (nonatomic, readonly, getter = isClear) BOOL clear; 39 | 40 | @property (nonatomic, strong, readonly) UIControl *overlayView; 41 | @property (nonatomic, strong, readonly) UIView *hudView; 42 | @property (nonatomic, strong, readonly) UILabel *stringLabel; 43 | @property (nonatomic, strong, readonly) UIImageView *imageView; 44 | @property (nonatomic, strong, readonly) TBActivityView *spinnerView; 45 | 46 | @property (nonatomic, readwrite) CGFloat progress; 47 | @property (nonatomic, readwrite) NSUInteger activityCount; 48 | @property (nonatomic, strong) CAShapeLayer *backgroundRingLayer; 49 | @property (nonatomic, strong) CAShapeLayer *ringLayer; 50 | 51 | @property (nonatomic, readonly) CGFloat visibleKeyboardHeight; 52 | @property (nonatomic, assign) UIOffset offsetFromCenter; 53 | 54 | - (void)showProgress:(float)progress 55 | status:(NSString*)string 56 | maskType:(SVProgressHUDMaskType)hudMaskType; 57 | 58 | - (void)showImage:(UIImage*)image 59 | status:(NSString*)status 60 | duration:(NSTimeInterval)duration; 61 | 62 | - (void)dismiss; 63 | 64 | - (void)setStatus:(NSString*)string; 65 | - (void)registerNotifications; 66 | - (NSDictionary *)notificationUserInfo; 67 | - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle; 68 | - (void)positionHUD:(NSNotification*)notification; 69 | - (NSTimeInterval)displayDurationForString:(NSString*)string; 70 | 71 | #if __IPHONE_OS_VERSION_MIN_REQUIRED < 50000 72 | - (UIColor *)hudBackgroundColor; 73 | - (UIColor *)hudForegroundColor; 74 | - (UIColor *)hudStatusShadowColor; 75 | - (UIColor *)hudRingBackgroundColor; 76 | - (UIColor *)hudRingForegroundColor; 77 | - (UIFont *)hudFont; 78 | - (UIImage *)hudSuccessImage; 79 | - (UIImage *)hudErrorImage; 80 | #endif 81 | 82 | @end 83 | 84 | 85 | @implementation SVProgressHUD 86 | 87 | @synthesize overlayView, hudView, maskType, fadeOutTimer, stringLabel, imageView, spinnerView, visibleKeyboardHeight; 88 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 89 | @synthesize hudBackgroundColor = _uiHudBgColor; 90 | @synthesize hudForegroundColor = _uiHudFgColor; 91 | @synthesize hudStatusShadowColor = _uiHudStatusShColor; 92 | @synthesize hudRingBackgroundColor = _uiHudRingBgColor; 93 | @synthesize hudRingForegroundColor = _uiHudRingFgColor; 94 | @synthesize hudFont = _uiHudFont; 95 | @synthesize hudSuccessImage = _uiHudSuccessImage; 96 | @synthesize hudErrorImage = _uiHudErrorImage; 97 | #endif 98 | 99 | 100 | + (SVProgressHUD*)sharedView { 101 | static dispatch_once_t once; 102 | static SVProgressHUD *sharedView; 103 | dispatch_once(&once, ^ { sharedView = [[self alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; }); 104 | return sharedView; 105 | } 106 | 107 | 108 | + (void)setStatus:(NSString *)string { 109 | [[self sharedView] setStatus:string]; 110 | } 111 | 112 | #pragma mark - Show Methods 113 | 114 | + (void)show { 115 | [[self sharedView] showProgress:-1 status:nil maskType:SVProgressHUDMaskTypeNone]; 116 | } 117 | 118 | + (void)showWithStatus:(NSString *)status { 119 | [[self sharedView] showProgress:-1 status:status maskType:SVProgressHUDMaskTypeNone]; 120 | } 121 | 122 | + (void)showWithMaskType:(SVProgressHUDMaskType)maskType { 123 | [[self sharedView] showProgress:-1 status:nil maskType:maskType]; 124 | } 125 | 126 | + (void)showWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType { 127 | [[self sharedView] showProgress:-1 status:status maskType:maskType]; 128 | } 129 | 130 | + (void)showProgress:(float)progress { 131 | [[self sharedView] showProgress:progress status:nil maskType:SVProgressHUDMaskTypeNone]; 132 | } 133 | 134 | + (void)showProgress:(float)progress status:(NSString *)status { 135 | [[self sharedView] showProgress:progress status:status maskType:SVProgressHUDMaskTypeNone]; 136 | } 137 | 138 | + (void)showProgress:(float)progress status:(NSString *)status maskType:(SVProgressHUDMaskType)maskType { 139 | [[self sharedView] showProgress:progress status:status maskType:maskType]; 140 | } 141 | 142 | #pragma mark - Show then dismiss methods 143 | 144 | + (void)showSuccessWithStatus:(NSString *)string { 145 | [self showImage:[[self sharedView] hudSuccessImage] status:string]; 146 | } 147 | 148 | + (void)showErrorWithStatus:(NSString *)string { 149 | NSTimeInterval displayInterval = [[SVProgressHUD sharedView] displayDurationForString:string]; 150 | [[self sharedView] showStringWithStatus:string duration:displayInterval]; 151 | } 152 | 153 | + (void)showImage:(UIImage *)image status:(NSString *)string { 154 | NSTimeInterval displayInterval = [[SVProgressHUD sharedView] displayDurationForString:string]; 155 | [[self sharedView] showImage:image status:string duration:displayInterval]; 156 | } 157 | 158 | -(void)showStringWithStatus:(NSString *)string duration:(NSTimeInterval )duration{ 159 | self.progress = -1; 160 | [self cancelRingLayerAnimation]; 161 | 162 | if(![self.class isVisible]) 163 | [self.class show]; 164 | 165 | self.imageView.image=nil; 166 | self.imageView.hidden = NO; 167 | 168 | self.stringLabel.text = string; 169 | [self updatePosition]; 170 | [self.spinnerView stopAnimate]; 171 | 172 | if(self.maskType != SVProgressHUDMaskTypeNone) { 173 | self.accessibilityLabel = string; 174 | self.isAccessibilityElement = YES; 175 | } else { 176 | self.hudView.accessibilityLabel = string; 177 | self.hudView.isAccessibilityElement = YES; 178 | } 179 | 180 | UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 181 | UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, string); 182 | 183 | self.fadeOutTimer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(dismiss) userInfo:nil repeats:NO]; 184 | [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes]; 185 | } 186 | #pragma mark - Dismiss Methods 187 | 188 | + (void)popActivity { 189 | [self sharedView].activityCount--; 190 | if([self sharedView].activityCount == 0) 191 | [[self sharedView] dismiss]; 192 | } 193 | 194 | + (void)dismiss { 195 | if ([self isVisible]) { 196 | [[self sharedView] dismiss]; 197 | } 198 | } 199 | 200 | 201 | #pragma mark - Offset 202 | 203 | + (void)setOffsetFromCenter:(UIOffset)offset { 204 | [self sharedView].offsetFromCenter = offset; 205 | } 206 | 207 | + (void)resetOffsetFromCenter { 208 | [self setOffsetFromCenter:UIOffsetZero]; 209 | } 210 | 211 | #pragma mark - Instance Methods 212 | 213 | - (id)initWithFrame:(CGRect)frame { 214 | 215 | if ((self = [super initWithFrame:frame])) { 216 | self.userInteractionEnabled = NO; 217 | self.backgroundColor = [UIColor clearColor]; 218 | self.alpha = 0; 219 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 220 | self.activityCount = 0; 221 | } 222 | 223 | return self; 224 | } 225 | 226 | - (void)drawRect:(CGRect)rect { 227 | 228 | CGContextRef context = UIGraphicsGetCurrentContext(); 229 | 230 | switch (self.maskType) { 231 | 232 | case SVProgressHUDMaskTypeBlack: { 233 | [[UIColor colorWithWhite:0 alpha:0.5] set]; 234 | CGContextFillRect(context, self.bounds); 235 | break; 236 | } 237 | 238 | case SVProgressHUDMaskTypeGradient: { 239 | 240 | size_t locationsCount = 2; 241 | CGFloat locations[2] = {0.0f, 1.0f}; 242 | CGFloat colors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f}; 243 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 244 | CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, locationsCount); 245 | CGColorSpaceRelease(colorSpace); 246 | 247 | CGFloat freeHeight = self.bounds.size.height - self.visibleKeyboardHeight; 248 | 249 | CGPoint center = CGPointMake(self.bounds.size.width/2, freeHeight/2); 250 | float radius = MIN(self.bounds.size.width , self.bounds.size.height) ; 251 | CGContextDrawRadialGradient (context, gradient, center, 0, center, radius, kCGGradientDrawsAfterEndLocation); 252 | CGGradientRelease(gradient); 253 | 254 | break; 255 | } 256 | } 257 | } 258 | 259 | - (void)updatePosition { 260 | 261 | CGFloat hudWidth = 100; 262 | CGFloat hudHeight = 100; 263 | CGFloat stringHeightBuffer = 20; 264 | CGFloat stringAndImageHeightBuffer = 80; 265 | 266 | CGFloat stringWidth = 0; 267 | CGFloat stringHeight = 0; 268 | CGRect labelRect = CGRectZero; 269 | 270 | NSString *string = self.stringLabel.text; 271 | // False if it's text-only 272 | BOOL imageUsed = (self.imageView.image) || (self.imageView.hidden); 273 | 274 | if(string) { 275 | CGSize constraintSize = CGSizeMake(200, 300); 276 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 277 | CGRect stringRect = [string boundingRectWithSize:constraintSize options:(NSStringDrawingUsesFontLeading|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin) attributes:@{NSFontAttributeName: self.stringLabel.font} context:NULL]; 278 | stringWidth = stringRect.size.width; 279 | stringHeight = stringRect.size.height; 280 | #else 281 | CGSize stringSize = [string sizeWithFont:self.stringLabel.font constrainedToSize:constraintSize]; 282 | stringWidth = stringSize.width; 283 | stringHeight = stringSize.height; 284 | #endif 285 | 286 | if (imageUsed) 287 | hudHeight = stringAndImageHeightBuffer + stringHeight; 288 | else 289 | hudHeight = stringHeightBuffer + stringHeight; 290 | 291 | if(stringWidth >= hudWidth) 292 | hudWidth = ceil(stringWidth/2)*2; 293 | hudWidth+=20; 294 | CGFloat labelRectY = imageUsed ? 66 : 9; 295 | 296 | // if(hudHeight > 100) { 297 | labelRect = CGRectMake(12, labelRectY, hudWidth, stringHeight); 298 | hudWidth+=24; 299 | // } else { 300 | // hudWidth+=24; 301 | // labelRect = CGRectMake(0, labelRectY, hudWidth, stringHeight); 302 | // } 303 | } 304 | 305 | self.hudView.bounds = CGRectMake(0, 0, hudWidth, hudHeight); 306 | 307 | if(string) 308 | self.imageView.center = CGPointMake(CGRectGetWidth(self.hudView.bounds)/2, 36); 309 | else 310 | self.imageView.center = CGPointMake(CGRectGetWidth(self.hudView.bounds)/2, CGRectGetHeight(self.hudView.bounds)/2); 311 | 312 | self.stringLabel.hidden = NO; 313 | self.stringLabel.frame = labelRect; 314 | 315 | if(string) { 316 | self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.hudView.bounds)/2)+0.5, 40.5); 317 | 318 | if(self.progress != -1) 319 | self.backgroundRingLayer.position = self.ringLayer.position = CGPointMake((CGRectGetWidth(self.hudView.bounds)/2), 36); 320 | } 321 | else { 322 | self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.hudView.bounds)/2)+0.5, ceil(self.hudView.bounds.size.height/2)+0.5); 323 | 324 | if(self.progress != -1) 325 | self.backgroundRingLayer.position = self.ringLayer.position = CGPointMake((CGRectGetWidth(self.hudView.bounds)/2), CGRectGetHeight(self.hudView.bounds)/2); 326 | } 327 | 328 | } 329 | 330 | - (void)setStatus:(NSString *)string { 331 | 332 | self.stringLabel.text = string; 333 | [self updatePosition]; 334 | 335 | } 336 | 337 | - (void)setFadeOutTimer:(NSTimer *)newTimer { 338 | 339 | if(fadeOutTimer) 340 | [fadeOutTimer invalidate], fadeOutTimer = nil; 341 | 342 | if(newTimer) 343 | fadeOutTimer = newTimer; 344 | } 345 | 346 | 347 | - (void)registerNotifications { 348 | [[NSNotificationCenter defaultCenter] addObserver:self 349 | selector:@selector(positionHUD:) 350 | name:UIApplicationDidChangeStatusBarOrientationNotification 351 | object:nil]; 352 | 353 | [[NSNotificationCenter defaultCenter] addObserver:self 354 | selector:@selector(positionHUD:) 355 | name:UIKeyboardWillHideNotification 356 | object:nil]; 357 | 358 | [[NSNotificationCenter defaultCenter] addObserver:self 359 | selector:@selector(positionHUD:) 360 | name:UIKeyboardDidHideNotification 361 | object:nil]; 362 | 363 | [[NSNotificationCenter defaultCenter] addObserver:self 364 | selector:@selector(positionHUD:) 365 | name:UIKeyboardWillShowNotification 366 | object:nil]; 367 | 368 | [[NSNotificationCenter defaultCenter] addObserver:self 369 | selector:@selector(positionHUD:) 370 | name:UIKeyboardDidShowNotification 371 | object:nil]; 372 | } 373 | 374 | 375 | - (NSDictionary *)notificationUserInfo 376 | { 377 | return (self.stringLabel.text ? @{SVProgressHUDStatusUserInfoKey : self.stringLabel.text} : nil); 378 | } 379 | 380 | 381 | - (void)positionHUD:(NSNotification*)notification { 382 | 383 | CGFloat keyboardHeight; 384 | double animationDuration = 0.0; 385 | 386 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 387 | 388 | if(notification) { 389 | NSDictionary* keyboardInfo = [notification userInfo]; 390 | CGRect keyboardFrame = [[keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue]; 391 | animationDuration = [[keyboardInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]; 392 | 393 | if(notification.name == UIKeyboardWillShowNotification || notification.name == UIKeyboardDidShowNotification) { 394 | if(UIInterfaceOrientationIsPortrait(orientation)) 395 | keyboardHeight = keyboardFrame.size.height; 396 | else 397 | keyboardHeight = keyboardFrame.size.width; 398 | } else 399 | keyboardHeight = 0; 400 | } else { 401 | keyboardHeight = self.visibleKeyboardHeight; 402 | } 403 | 404 | CGRect orientationFrame = [UIScreen mainScreen].bounds; 405 | CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame; 406 | 407 | if(UIInterfaceOrientationIsLandscape(orientation)) { 408 | float temp = orientationFrame.size.width; 409 | orientationFrame.size.width = orientationFrame.size.height; 410 | orientationFrame.size.height = temp; 411 | 412 | temp = statusBarFrame.size.width; 413 | statusBarFrame.size.width = statusBarFrame.size.height; 414 | statusBarFrame.size.height = temp; 415 | } 416 | 417 | CGFloat activeHeight = orientationFrame.size.height; 418 | 419 | if(keyboardHeight > 0) 420 | activeHeight += statusBarFrame.size.height*2; 421 | 422 | activeHeight -= keyboardHeight; 423 | CGFloat posY = floor(activeHeight*0.45); 424 | CGFloat posX = orientationFrame.size.width/2; 425 | 426 | CGPoint newCenter; 427 | CGFloat rotateAngle; 428 | 429 | switch (orientation) { 430 | case UIInterfaceOrientationPortraitUpsideDown: 431 | rotateAngle = M_PI; 432 | newCenter = CGPointMake(posX, orientationFrame.size.height-posY); 433 | break; 434 | case UIInterfaceOrientationLandscapeLeft: 435 | rotateAngle = -M_PI/2.0f; 436 | newCenter = CGPointMake(posY, posX); 437 | break; 438 | case UIInterfaceOrientationLandscapeRight: 439 | rotateAngle = M_PI/2.0f; 440 | newCenter = CGPointMake(orientationFrame.size.height-posY, posX); 441 | break; 442 | default: // as UIInterfaceOrientationPortrait 443 | rotateAngle = 0.0; 444 | newCenter = CGPointMake(posX, posY); 445 | break; 446 | } 447 | 448 | if(notification) { 449 | [UIView animateWithDuration:animationDuration 450 | delay:0 451 | options:UIViewAnimationOptionAllowUserInteraction 452 | animations:^{ 453 | [self moveToPoint:newCenter rotateAngle:rotateAngle]; 454 | } completion:NULL]; 455 | } 456 | 457 | else { 458 | [self moveToPoint:newCenter rotateAngle:rotateAngle]; 459 | } 460 | 461 | } 462 | 463 | - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle { 464 | self.hudView.transform = CGAffineTransformMakeRotation(angle); 465 | self.hudView.center = CGPointMake(newCenter.x + self.offsetFromCenter.horizontal, newCenter.y + self.offsetFromCenter.vertical); 466 | } 467 | 468 | - (void)overlayViewDidReceiveTouchEvent:(id)sender forEvent:(UIEvent *)event { 469 | [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidReceiveTouchEventNotification object:event]; 470 | } 471 | 472 | #pragma mark - Master show/dismiss methods 473 | 474 | - (void)showProgress:(float)progress status:(NSString*)string maskType:(SVProgressHUDMaskType)hudMaskType { 475 | 476 | if(!self.overlayView.superview){ 477 | NSEnumerator *frontToBackWindows = [[[UIApplication sharedApplication]windows]reverseObjectEnumerator]; 478 | 479 | for (UIWindow *window in frontToBackWindows) 480 | if (window.windowLevel == UIWindowLevelNormal) { 481 | [window addSubview:self.overlayView]; 482 | break; 483 | } 484 | } 485 | 486 | if(!self.superview) 487 | [self.overlayView addSubview:self]; 488 | 489 | self.fadeOutTimer = nil; 490 | self.imageView.hidden = YES; 491 | self.maskType = hudMaskType; 492 | self.progress = progress; 493 | 494 | self.stringLabel.text = string; 495 | [self updatePosition]; 496 | 497 | if(progress >= 0) { 498 | self.imageView.image = nil; 499 | self.imageView.hidden = NO; 500 | [self.spinnerView stopAnimate]; 501 | self.ringLayer.strokeEnd = progress; 502 | 503 | if(progress == 0) 504 | self.activityCount++; 505 | } 506 | else { 507 | self.activityCount++; 508 | [self cancelRingLayerAnimation]; 509 | [self.spinnerView startAnimate]; 510 | } 511 | 512 | if(self.maskType != SVProgressHUDMaskTypeNone) { 513 | self.overlayView.userInteractionEnabled = YES; 514 | self.accessibilityLabel = string; 515 | self.isAccessibilityElement = YES; 516 | } 517 | else { 518 | self.overlayView.userInteractionEnabled = NO; 519 | self.hudView.accessibilityLabel = string; 520 | self.hudView.isAccessibilityElement = YES; 521 | } 522 | 523 | [self.overlayView setHidden:NO]; 524 | [self positionHUD:nil]; 525 | 526 | if(self.alpha != 1) { 527 | NSDictionary *userInfo = [self notificationUserInfo]; 528 | [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillAppearNotification 529 | object:nil 530 | userInfo:userInfo]; 531 | 532 | [self registerNotifications]; 533 | self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1.3, 1.3); 534 | 535 | if(self.isClear) { 536 | self.alpha = 1; 537 | self.hudView.alpha = 0; 538 | } 539 | 540 | [UIView animateWithDuration:0.15 541 | delay:0 542 | options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState 543 | animations:^{ 544 | self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1/1.3, 1/1.3); 545 | 546 | if(self.isClear){ // handle iOS 7 UIToolbar not answer well to hierarchy opacity change 547 | self.hudView.alpha = 1; 548 | } 549 | else 550 | self.alpha = 1; 551 | } 552 | completion:^(BOOL finished){ 553 | [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidAppearNotification 554 | object:nil 555 | userInfo:userInfo]; 556 | UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 557 | UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, string); 558 | }]; 559 | 560 | [self setNeedsDisplay]; 561 | } 562 | } 563 | 564 | 565 | - (void)showImage:(UIImage *)image status:(NSString *)string duration:(NSTimeInterval)duration { 566 | self.progress = -1; 567 | [self cancelRingLayerAnimation]; 568 | 569 | if(![self.class isVisible]) 570 | [self.class show]; 571 | 572 | self.imageView.image = image; 573 | self.imageView.hidden = NO; 574 | 575 | self.stringLabel.text = string; 576 | [self updatePosition]; 577 | [self.spinnerView stopAnimate]; 578 | 579 | if(self.maskType != SVProgressHUDMaskTypeNone) { 580 | self.accessibilityLabel = string; 581 | self.isAccessibilityElement = YES; 582 | } else { 583 | self.hudView.accessibilityLabel = string; 584 | self.hudView.isAccessibilityElement = YES; 585 | } 586 | 587 | UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 588 | UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, string); 589 | 590 | self.fadeOutTimer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(dismiss) userInfo:nil repeats:NO]; 591 | [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes]; 592 | } 593 | 594 | - (void)dismiss { 595 | NSDictionary *userInfo = [self notificationUserInfo]; 596 | [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillDisappearNotification 597 | object:nil 598 | userInfo:userInfo]; 599 | 600 | self.activityCount = 0; 601 | [UIView animateWithDuration:0.15 602 | delay:0 603 | options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction 604 | animations:^{ 605 | self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 0.8, 0.8); 606 | if(self.isClear) // handle iOS 7 UIToolbar not answer well to hierarchy opacity change 607 | self.hudView.alpha = 0; 608 | else 609 | self.alpha = 0; 610 | } 611 | completion:^(BOOL finished){ 612 | if(self.alpha == 0 || self.hudView.alpha == 0) { 613 | self.alpha = 0; 614 | self.hudView.alpha = 0; 615 | 616 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 617 | [self cancelRingLayerAnimation]; 618 | [hudView removeFromSuperview]; 619 | hudView = nil; 620 | 621 | [overlayView removeFromSuperview]; 622 | overlayView = nil; 623 | 624 | UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 625 | 626 | [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidDisappearNotification 627 | object:nil 628 | userInfo:userInfo]; 629 | 630 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 631 | // Tell the rootViewController to update the StatusBar appearance 632 | UIViewController *rootController = [[UIApplication sharedApplication] keyWindow].rootViewController; 633 | if ([rootController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { 634 | [rootController setNeedsStatusBarAppearanceUpdate]; 635 | } 636 | #endif 637 | // uncomment to make sure UIWindow is gone from app.windows 638 | //NSLog(@"%@", [UIApplication sharedApplication].windows); 639 | //NSLog(@"keyWindow = %@", [UIApplication sharedApplication].keyWindow); 640 | } 641 | }]; 642 | } 643 | 644 | 645 | #pragma mark - 646 | #pragma mark Ring progress animation 647 | 648 | - (CAShapeLayer *)ringLayer { 649 | if(!_ringLayer) { 650 | CGPoint center = CGPointMake(CGRectGetWidth(hudView.frame)/2, CGRectGetHeight(hudView.frame)/2); 651 | _ringLayer = [self createRingLayerWithCenter:center radius:SVProgressHUDRingRadius lineWidth:SVProgressHUDRingThickness color:self.hudRingForegroundColor]; 652 | [self.hudView.layer addSublayer:_ringLayer]; 653 | } 654 | return _ringLayer; 655 | } 656 | 657 | - (CAShapeLayer *)backgroundRingLayer { 658 | if(!_backgroundRingLayer) { 659 | CGPoint center = CGPointMake(CGRectGetWidth(hudView.frame)/2, CGRectGetHeight(hudView.frame)/2); 660 | _backgroundRingLayer = [self createRingLayerWithCenter:center radius:SVProgressHUDRingRadius lineWidth:SVProgressHUDRingThickness color:self.hudRingBackgroundColor]; 661 | _backgroundRingLayer.strokeEnd = 1; 662 | [self.hudView.layer addSublayer:_backgroundRingLayer]; 663 | } 664 | return _backgroundRingLayer; 665 | } 666 | 667 | - (void)cancelRingLayerAnimation { 668 | [CATransaction begin]; 669 | [CATransaction setDisableActions:YES]; 670 | [hudView.layer removeAllAnimations]; 671 | 672 | _ringLayer.strokeEnd = 0.0f; 673 | if (_ringLayer.superlayer) { 674 | [_ringLayer removeFromSuperlayer]; 675 | } 676 | _ringLayer = nil; 677 | 678 | if (_backgroundRingLayer.superlayer) { 679 | [_backgroundRingLayer removeFromSuperlayer]; 680 | } 681 | _backgroundRingLayer = nil; 682 | 683 | [CATransaction commit]; 684 | } 685 | 686 | - (CGPoint)pointOnCircleWithCenter:(CGPoint)center radius:(double)radius angleInDegrees:(double)angleInDegrees { 687 | float x = (float)(radius * cos(angleInDegrees * M_PI / 180)) + radius; 688 | float y = (float)(radius * sin(angleInDegrees * M_PI / 180)) + radius; 689 | return CGPointMake(x, y); 690 | } 691 | 692 | 693 | - (UIBezierPath *)createCirclePathWithCenter:(CGPoint)center radius:(CGFloat)radius sampleCount:(NSInteger)sampleCount { 694 | 695 | UIBezierPath *smoothedPath = [UIBezierPath bezierPath]; 696 | CGPoint startPoint = [self pointOnCircleWithCenter:center radius:radius angleInDegrees:-90]; 697 | 698 | [smoothedPath moveToPoint:startPoint]; 699 | 700 | CGFloat delta = 360.0f/sampleCount; 701 | CGFloat angleInDegrees = -90; 702 | for (NSInteger i=1; i= 70000 759 | hudView = [[UIView alloc] initWithFrame:CGRectZero]; 760 | // ((UIView *)hudView).translucent = YES; 761 | ((UIView *)hudView).backgroundColor= self.hudBackgroundColor; 762 | #else 763 | hudView = [[UIView alloc] initWithFrame:CGRectZero]; 764 | 765 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 766 | 767 | // UIAppearance is used when iOS >= 5.0 768 | hudView.backgroundColor = self.hudBackgroundColor; 769 | #endif 770 | #endif 771 | 772 | hudView.layer.cornerRadius = 3; 773 | hudView.layer.masksToBounds = YES; 774 | 775 | hudView.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin | 776 | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin); 777 | 778 | [self addSubview:hudView]; 779 | } 780 | return hudView; 781 | } 782 | 783 | - (UILabel *)stringLabel { 784 | if (stringLabel == nil) { 785 | stringLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 786 | stringLabel.backgroundColor = [UIColor clearColor]; 787 | stringLabel.adjustsFontSizeToFitWidth = YES; 788 | #if __IPHONE_OS_VERSION_MIN_REQUIRED < 60000 789 | stringLabel.textAlignment = UITextAlignmentCenter; 790 | #else 791 | stringLabel.textAlignment = NSTextAlignmentCenter; 792 | #endif 793 | 794 | stringLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters; 795 | 796 | // UIAppearance is used when iOS >= 5.0 797 | stringLabel.textColor = self.hudForegroundColor; 798 | stringLabel.font = self.hudFont; 799 | 800 | #if __IPHONE_OS_VERSION_MIN_REQUIRED < 70000 801 | stringLabel.shadowColor = self.hudStatusShadowColor; 802 | stringLabel.shadowOffset = CGSizeMake(0, -1); 803 | #endif 804 | stringLabel.numberOfLines = 0; 805 | } 806 | 807 | if(!stringLabel.superview) 808 | [self.hudView addSubview:stringLabel]; 809 | 810 | return stringLabel; 811 | } 812 | 813 | - (UIImageView *)imageView { 814 | if (imageView == nil) 815 | imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 28, 28)]; 816 | 817 | if(!imageView.superview) 818 | [self.hudView addSubview:imageView]; 819 | 820 | return imageView; 821 | } 822 | 823 | - (TBActivityView *)spinnerView { 824 | if (spinnerView == nil) { 825 | spinnerView = [[TBActivityView alloc] initWithFrame:CGRectMake(0, 0, 320, 20)]; 826 | 827 | } 828 | 829 | if(!spinnerView.superview) 830 | [self.hudView addSubview:spinnerView]; 831 | 832 | return spinnerView; 833 | } 834 | 835 | - (CGFloat)visibleKeyboardHeight { 836 | 837 | UIWindow *keyboardWindow = nil; 838 | for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) { 839 | if(![[testWindow class] isEqual:[UIWindow class]]) { 840 | keyboardWindow = testWindow; 841 | break; 842 | } 843 | } 844 | 845 | for (__strong UIView *possibleKeyboard in [keyboardWindow subviews]) { 846 | if([possibleKeyboard isKindOfClass:NSClassFromString(@"UIPeripheralHostView")] || [possibleKeyboard isKindOfClass:NSClassFromString(@"UIKeyboard")]) 847 | return possibleKeyboard.bounds.size.height; 848 | } 849 | 850 | return 0; 851 | } 852 | 853 | #pragma mark - UIAppearance getters 854 | 855 | - (UIColor *)hudBackgroundColor { 856 | 857 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 858 | if(_uiHudBgColor == nil) { 859 | _uiHudBgColor = [[[self class] appearance] hudBackgroundColor]; 860 | } 861 | 862 | if(_uiHudBgColor != nil) { 863 | return _uiHudBgColor; 864 | } 865 | #endif 866 | 867 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 868 | return [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7]; 869 | #else 870 | return [UIColor colorWithWhite:0 alpha:0.8]; 871 | #endif 872 | } 873 | 874 | - (UIColor *)hudForegroundColor { 875 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 876 | if(_uiHudFgColor == nil) { 877 | _uiHudFgColor = [[[self class] appearance] hudForegroundColor]; 878 | } 879 | 880 | if(_uiHudFgColor != nil) { 881 | return _uiHudFgColor; 882 | } 883 | #endif 884 | 885 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 886 | return [UIColor colorWithWhite:1 alpha:0.8]; 887 | #else 888 | return [UIColor whiteColor]; 889 | #endif 890 | } 891 | 892 | - (UIColor *)hudRingBackgroundColor { 893 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 894 | if(_uiHudRingBgColor == nil) { 895 | _uiHudRingBgColor = [[[self class] appearance] hudRingBackgroundColor]; 896 | } 897 | 898 | if(_uiHudRingBgColor != nil) { 899 | return _uiHudRingBgColor; 900 | } 901 | #endif 902 | 903 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 904 | return [UIColor whiteColor]; 905 | #else 906 | return [UIColor colorWithWhite:0 alpha:0.8]; 907 | #endif 908 | } 909 | 910 | - (UIColor *)hudRingForegroundColor { 911 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 912 | if(_uiHudRingFgColor == nil) { 913 | _uiHudRingFgColor = [[[self class] appearance] hudRingForegroundColor]; 914 | } 915 | 916 | if(_uiHudRingFgColor != nil) { 917 | return _uiHudRingFgColor; 918 | } 919 | #endif 920 | 921 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 922 | return self.tintColor; 923 | #else 924 | return [UIColor whiteColor]; 925 | #endif 926 | } 927 | 928 | - (UIColor *)hudStatusShadowColor { 929 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 930 | if(_uiHudStatusShColor == nil) { 931 | _uiHudStatusShColor = [[[self class] appearance] hudStatusShadowColor]; 932 | } 933 | 934 | if(_uiHudStatusShColor != nil) { 935 | return _uiHudStatusShColor; 936 | } 937 | #endif 938 | 939 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 940 | return [UIColor colorWithWhite:200.0f/255.0f alpha:0.8]; 941 | #else 942 | return [UIColor blackColor]; 943 | #endif 944 | } 945 | 946 | - (UIFont *)hudFont { 947 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 948 | if(_uiHudFont == nil) { 949 | _uiHudFont = [[[self class] appearance] hudFont]; 950 | } 951 | 952 | if(_uiHudFont != nil) { 953 | return _uiHudFont; 954 | } 955 | #endif 956 | 957 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 958 | return [UIFont systemFontOfSize:15]; 959 | #else 960 | return [UIFont boldSystemFontOfSize:15]; 961 | #endif 962 | } 963 | 964 | - (UIImage *)hudSuccessImage { 965 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 966 | if(_uiHudSuccessImage == nil) { 967 | _uiHudSuccessImage = [[[self class] appearance] hudSuccessImage]; 968 | } 969 | 970 | if(_uiHudSuccessImage != nil) { 971 | return _uiHudSuccessImage; 972 | } 973 | #endif 974 | 975 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 976 | return [UIImage imageNamed:@"SVProgressHUD.bundle/success"]; 977 | #else 978 | return [UIImage imageNamed:@"SVProgressHUD.bundle/success.png"]; 979 | #endif 980 | } 981 | 982 | - (UIImage *)hudErrorImage { 983 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000 984 | if(_uiHudErrorImage == nil) { 985 | _uiHudErrorImage = [[[self class] appearance] hudErrorImage]; 986 | } 987 | 988 | if(_uiHudErrorImage != nil) { 989 | return _uiHudErrorImage; 990 | } 991 | #endif 992 | 993 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000 994 | return [UIImage imageNamed:@"SVProgressHUD.bundle/error"]; 995 | #else 996 | return [UIImage imageNamed:@"SVProgressHUD.bundle/error.png"]; 997 | #endif 998 | } 999 | 1000 | @end 1001 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/TBActivityView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TBActivityView.h 3 | // TBActivityView 4 | // 5 | // Created by MacBook Pro on 14-6-19. 6 | // Copyright (c) 2014年 zhaoonline. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TBActivityView : UIView 12 | /** 13 | * 小方块个数 14 | */ 15 | @property(readwrite , nonatomic) NSUInteger numberOfRect; 16 | 17 | /** 18 | * 小方块背景色 19 | */ 20 | @property(strong , nonatomic) UIColor* rectBackgroundColor; 21 | 22 | /** 23 | * self.frame.size 24 | */ 25 | @property(readwrite , nonatomic) CGSize defaultSize; 26 | 27 | /** 28 | * 小方块之间的间距 29 | */ 30 | @property(readwrite , nonatomic) CGFloat spacing; 31 | 32 | /** 33 | * 开始动画 34 | */ 35 | -(void)startAnimate; 36 | 37 | 38 | /** 39 | * 结束动画 40 | */ 41 | -(void)stopAnimate; 42 | @end 43 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/SVProgressHUD/TBActivityView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TBActivityView.m 3 | // TBActivityView 4 | // 5 | // Created by MacBook Pro on 14-6-19. 6 | // Copyright (c) 2014年 zhaoonline. All rights reserved. 7 | // 8 | 9 | #import "TBActivityView.h" 10 | /** 11 | * defaultSize为空时,使用默认normalSize 12 | */ 13 | static CGSize normalSize = {320,50}; 14 | 15 | @implementation TBActivityView 16 | 17 | - (id)initWithFrame:(CGRect)frame 18 | { 19 | self = [super initWithFrame:frame]; 20 | if (self) { 21 | [self setDefaultAttribute]; 22 | } 23 | return self; 24 | } 25 | 26 | 27 | -(instancetype)init 28 | { 29 | self = [super init]; 30 | 31 | if (self) { 32 | [self setDefaultAttribute]; 33 | } 34 | 35 | return self; 36 | } 37 | 38 | 39 | /** 40 | * 设置默认属性 41 | */ 42 | -(void)setDefaultAttribute 43 | { 44 | _numberOfRect = 6; 45 | self.rectBackgroundColor= [UIColor whiteColor]; 46 | _defaultSize = normalSize; 47 | _spacing =1; 48 | 49 | 50 | [self setBackgroundColor:[UIColor clearColor]]; 51 | if (CGRectEqualToRect(self.frame, CGRectZero)) { 52 | [self setFrame:CGRectMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame), _defaultSize.width, _defaultSize.height)]; 53 | 54 | } 55 | else 56 | { 57 | _defaultSize = self.frame.size; 58 | } 59 | } 60 | 61 | 62 | -(CAAnimation*)addAnimateWithDelay:(CGFloat)delay 63 | { 64 | CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.x"]; 65 | animation.repeatCount = MAXFLOAT; 66 | animation.removedOnCompletion = YES; 67 | animation.autoreverses = NO; 68 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 69 | animation.fromValue = [NSNumber numberWithFloat:0]; 70 | animation.toValue = [NSNumber numberWithFloat:M_PI]; 71 | animation.duration = _numberOfRect * 0.1; //第一个翻转一周,最后一个开始翻转 72 | animation.beginTime = CACurrentMediaTime() + delay; 73 | 74 | return animation; 75 | } 76 | 77 | 78 | /** 79 | * 添加矩形 80 | */ 81 | -(void)addRect 82 | { 83 | 84 | [self removeRect]; 85 | [self setHidden:NO]; 86 | 87 | for (int i = 0; i < _numberOfRect; i++) { 88 | 89 | UIView* rectView = [[UIView alloc] initWithFrame:CGRectMake((320 - _numberOfRect*(_defaultSize.height / 2. + _spacing))/2. + i *(_defaultSize.height / 2. + _spacing) , 0, _defaultSize.height/3., _defaultSize.height)]; 90 | [rectView setBackgroundColor:_rectBackgroundColor]; 91 | [rectView.layer addAnimation:[self addAnimateWithDelay:i*0.1] forKey:@"TBRotate"]; 92 | [self addSubview:rectView]; 93 | 94 | 95 | } 96 | 97 | 98 | } 99 | 100 | /** 101 | * 移除矩形 102 | */ 103 | -(void)removeRect 104 | { 105 | if (self.subviews.count) { 106 | [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 107 | } 108 | 109 | [self setHidden:YES]; 110 | } 111 | 112 | 113 | 114 | - (void)startAnimate 115 | { 116 | [self addRect]; 117 | } 118 | 119 | 120 | - (void)stopAnimate 121 | { 122 | [self removeRect]; 123 | } 124 | /* 125 | // Only override drawRect: if you perform custom drawing. 126 | // An empty implementation adversely affects performance during animation. 127 | - (void)drawRect:(CGRect)rect 128 | { 129 | // Drawing code 130 | } 131 | */ 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/WSLineChartView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WSLineView.h 3 | // 3333 4 | // 5 | // Created by iMac on 16/11/10. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WSLineChartView : UIView 12 | 13 | /*** 14 | * xTitleArray: X轴数据数组 15 | * yValueArray: 数据值数组 16 | * yMax: Y轴最大值 17 | * yMin: Y轴最小值 18 | * yTypeName: 代表Y轴是什么类型 19 | * xTypeName: 代表X轴是什么类型 20 | * unit: 长按时弹出的数据单位 21 | * ***/ 22 | - (id)initWithFrame:(CGRect)frame xTitleArray:(NSArray*)xTitleArray yValueArray:(NSArray*)yValueArray yMax:(CGFloat)yMax yMin:(CGFloat)yMin yTypeName:(NSString*)yTypeName xTypeName:(NSString*)xTypeName unit:(NSString*)unit; 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/WSLineChartView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WSLineView.m 3 | // 3333 4 | // 5 | // Created by iMac on 16/11/10. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import "WSLineChartView.h" 10 | #import "YAxisView.h" 11 | #import "XAxisView.h" 12 | #import "SVProgressHUD.h" 13 | 14 | 15 | #define leftMargin 45 16 | //#define defaultSpace 5 17 | #define lastSpace 10 18 | 19 | 20 | 21 | @interface WSLineChartView () 22 | 23 | @property (strong, nonatomic) NSArray *xTitleArray; 24 | @property (strong, nonatomic) NSArray *yValueArray; 25 | @property (assign, nonatomic) CGFloat yMax; 26 | @property (assign, nonatomic) CGFloat yMin; 27 | @property (strong, nonatomic) NSString *xTypeName; 28 | @property (strong, nonatomic) NSString *yTypeName; 29 | @property (strong, nonatomic) NSString *unit; 30 | 31 | @property (strong, nonatomic) YAxisView *yAxisView; 32 | @property (strong, nonatomic) XAxisView *xAxisView; 33 | @property (strong, nonatomic) UIScrollView *scrollView; 34 | @property (assign, nonatomic) CGFloat pointGap; 35 | @property (assign, nonatomic) CGFloat defaultSpace;//X轴点之间的间隔 36 | 37 | @property (assign, nonatomic) CGFloat moveDistance; 38 | 39 | @end 40 | 41 | @implementation WSLineChartView 42 | 43 | - (id)initWithFrame:(CGRect)frame xTitleArray:(NSArray*)xTitleArray yValueArray:(NSArray*)yValueArray yMax:(CGFloat)yMax yMin:(CGFloat)yMin yTypeName:(NSString*)yTypeName xTypeName:(NSString*)xTypeName unit:(NSString*)unit { 44 | 45 | self = [super initWithFrame:frame]; 46 | if (self) { 47 | self.backgroundColor = [UIColor clearColor]; 48 | 49 | self.xTitleArray = xTitleArray; 50 | self.yValueArray = yValueArray; 51 | self.yMax = yMax; 52 | self.yMin = yMin; 53 | self.xTypeName = xTypeName; 54 | self.yTypeName = yTypeName; 55 | self.unit = unit; 56 | 57 | if (xTitleArray.count > 600) { 58 | _defaultSpace = 5; 59 | } 60 | else if (xTitleArray.count > 400 && xTitleArray.count <= 600){ 61 | _defaultSpace = 10; 62 | } 63 | else if (xTitleArray.count > 200 && xTitleArray.count <= 400){ 64 | _defaultSpace = 20; 65 | } 66 | else if (xTitleArray.count > 100 && xTitleArray.count <= 200){ 67 | _defaultSpace = 30; 68 | } 69 | else if (xTitleArray.count > 10 && xTitleArray.count <= 100){ 70 | _defaultSpace = 40; 71 | } 72 | else { 73 | _defaultSpace = (wsScreenWidth-leftMargin)/xTitleArray.count; 74 | } 75 | 76 | 77 | self.pointGap = (wsScreenWidth-leftMargin)/xTitleArray.count; 78 | 79 | 80 | [self creatYAxisView]; 81 | 82 | [self creatXAxisView]; 83 | 84 | // 2. 捏合手势 85 | UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGesture:)]; 86 | [self.xAxisView addGestureRecognizer:pinch]; 87 | 88 | //长按手势 89 | UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(event_longPressAction:)]; 90 | [self.xAxisView addGestureRecognizer:longPress]; 91 | 92 | 93 | } 94 | 95 | return self; 96 | } 97 | 98 | - (void)creatYAxisView { 99 | 100 | self.yAxisView = [[YAxisView alloc]initWithFrame:CGRectMake(0, 0, leftMargin, self.frame.size.height) yMax:self.yMax yMin:self.yMin]; 101 | [self addSubview:self.yAxisView]; 102 | 103 | } 104 | 105 | - (void)creatXAxisView { 106 | 107 | _scrollView = [[UIScrollView alloc]initWithFrame:CGRectMake(leftMargin, 0, self.frame.size.width-leftMargin, self.frame.size.height)]; 108 | _scrollView.showsHorizontalScrollIndicator = NO; 109 | _scrollView.bounces = NO; 110 | _scrollView.scrollsToTop = NO; 111 | [self addSubview:_scrollView]; 112 | 113 | self.xAxisView = [[XAxisView alloc] initWithFrame:CGRectMake(0, 0, self.xTitleArray.count * self.pointGap + lastSpace, self.frame.size.height) xTitleArray:self.xTitleArray yValueArray:self.yValueArray yMax:self.yMax yMin:self.yMin yTypeName:self.yTypeName xTypeName:self.xTypeName unit:self.unit]; 114 | 115 | [_scrollView addSubview:self.xAxisView]; 116 | 117 | _scrollView.contentSize = self.xAxisView.frame.size; 118 | 119 | } 120 | 121 | // 捏合手势监听方法 122 | - (void)pinchGesture:(UIPinchGestureRecognizer *)recognizer 123 | { 124 | if (recognizer.state == 3) { 125 | 126 | if (self.xAxisView.frame.size.width-lastSpace <= self.scrollView.frame.size.width) { //当缩小到小于屏幕宽时,松开回复屏幕宽度 127 | 128 | CGFloat scale = self.scrollView.frame.size.width / (self.xAxisView.frame.size.width-lastSpace); 129 | 130 | self.pointGap *= scale; 131 | 132 | [UIView animateWithDuration:0.25 animations:^{ 133 | 134 | CGRect frame = self.xAxisView.frame; 135 | frame.size.width = self.scrollView.frame.size.width+lastSpace; 136 | self.xAxisView.frame = frame; 137 | }]; 138 | 139 | self.xAxisView.pointGap = self.pointGap; 140 | 141 | }else if (self.xAxisView.frame.size.width-lastSpace >= self.xTitleArray.count * _defaultSpace){ 142 | 143 | [UIView animateWithDuration:0.25 animations:^{ 144 | CGRect frame = self.xAxisView.frame; 145 | frame.size.width = self.xTitleArray.count * _defaultSpace + lastSpace; 146 | self.xAxisView.frame = frame; 147 | 148 | }]; 149 | 150 | self.pointGap = _defaultSpace; 151 | 152 | self.xAxisView.pointGap = self.pointGap; 153 | } 154 | }else{ 155 | 156 | CGFloat currentIndex,leftMagin; 157 | if( recognizer.numberOfTouches == 2 ) { 158 | //2.获取捏合中心点 -> 捏合中心点距离scrollviewcontent左侧的距离 159 | CGPoint p1 = [recognizer locationOfTouch:0 inView:self.xAxisView]; 160 | CGPoint p2 = [recognizer locationOfTouch:1 inView:self.xAxisView]; 161 | CGFloat centerX = (p1.x+p2.x)/2; 162 | leftMagin = centerX - self.scrollView.contentOffset.x; 163 | 164 | currentIndex = centerX / self.pointGap; 165 | 166 | 167 | self.pointGap *= recognizer.scale; 168 | self.pointGap = self.pointGap > _defaultSpace ? _defaultSpace : self.pointGap; 169 | if (self.pointGap == _defaultSpace) { 170 | 171 | [SVProgressHUD showErrorWithStatus:@"已经放至最大"]; 172 | } 173 | self.xAxisView.pointGap = self.pointGap; 174 | recognizer.scale = 1.0; 175 | 176 | self.xAxisView.frame = CGRectMake(0, 0, self.xTitleArray.count * self.pointGap + lastSpace, self.frame.size.height); 177 | 178 | self.scrollView.contentOffset = CGPointMake(currentIndex*self.pointGap-leftMagin, 0); 179 | // NSLog(@"contentOffset = %f",self.scrollView.contentOffset.x); 180 | 181 | } 182 | 183 | 184 | 185 | 186 | 187 | } 188 | 189 | self.scrollView.contentSize = CGSizeMake(self.xAxisView.frame.size.width, 0); 190 | 191 | 192 | 193 | 194 | } 195 | 196 | 197 | - (void)event_longPressAction:(UILongPressGestureRecognizer *)longPress { 198 | 199 | if(UIGestureRecognizerStateChanged == longPress.state || UIGestureRecognizerStateBegan == longPress.state) { 200 | 201 | CGPoint location = [longPress locationInView:self.xAxisView]; 202 | 203 | //相对于屏幕的位置 204 | CGPoint screenLoc = CGPointMake(location.x - self.scrollView.contentOffset.x, location.y); 205 | [self.xAxisView setScreenLoc:screenLoc]; 206 | 207 | if (ABS(location.x - _moveDistance) > self.pointGap) { //不能长按移动一点点就重新绘图 要让定位的点改变了再重新绘图 208 | 209 | [self.xAxisView setIsShowLabel:YES]; 210 | [self.xAxisView setIsLongPress:YES]; 211 | self.xAxisView.currentLoc = location; 212 | _moveDistance = location.x; 213 | } 214 | } 215 | 216 | if(longPress.state == UIGestureRecognizerStateEnded) 217 | { 218 | _moveDistance = 0; 219 | //恢复scrollView的滑动 220 | [self.xAxisView setIsLongPress:NO]; 221 | [self.xAxisView setIsShowLabel:NO]; 222 | 223 | } 224 | } 225 | 226 | 227 | 228 | @end 229 | 230 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/XAxisView.h: -------------------------------------------------------------------------------- 1 | // 2 | // xAxisView.h 3 | // 3333 4 | // 5 | // Created by iMac on 16/11/10. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import 10 | #define wsScreenWidth [UIScreen mainScreen].bounds.size.width 11 | 12 | @interface XAxisView : UIView 13 | 14 | 15 | @property (assign, nonatomic) CGFloat pointGap;//点之间的距离 16 | @property (assign,nonatomic)BOOL isShowLabel;//是否显示文字 17 | 18 | @property (assign,nonatomic)BOOL isLongPress;//是不是长按状态 19 | @property (assign, nonatomic) CGPoint currentLoc; //长按时当前定位位置 20 | @property (assign, nonatomic) CGPoint screenLoc; //相对于屏幕位置 21 | 22 | /*** 23 | * xTitleArray: X轴数据数组 24 | * yValueArray: 数据值数组 25 | * yMax: Y轴最大值 26 | * yMin: Y轴最小值 27 | * yTypeName: 代表Y轴是什么类型 28 | * xTypeName: 代表X轴是什么类型 29 | * unit: 长按时弹出的数据单位 30 | * ***/ 31 | - (id)initWithFrame:(CGRect)frame xTitleArray:(NSArray*)xTitleArray yValueArray:(NSArray*)yValueArray yMax:(CGFloat)yMax yMin:(CGFloat)yMin yTypeName:(NSString*)yTypeName xTypeName:(NSString*)xTypeName unit:(NSString*)unit; 32 | 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/XAxisView.m: -------------------------------------------------------------------------------- 1 | // 2 | // xAxisView.m 3 | // 3333 4 | // 5 | // Created by iMac on 16/11/10. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import "XAxisView.h" 10 | #define topMargin 50 // 为顶部留出的空白 11 | #define kChartLineColor [UIColor grayColor] 12 | #define kChartTextColor [UIColor blackColor] 13 | #define pointColor [UIColor colorWithRed:27/255.0 green:168/255.0 blue:248/255.0 alpha:.5] 14 | #define leftMargin 45 15 | #define wsRGBA(r, g, b, a) ([UIColor colorWithRed:(r / 255.0) green:(g / 255.0) blue:(b / 255.0) alpha:a]) 16 | 17 | 18 | 19 | @interface XAxisView () 20 | 21 | @property (strong, nonatomic) NSArray *xTitleArray; 22 | @property (strong, nonatomic) NSArray *yValueArray; 23 | @property (assign, nonatomic) CGFloat yMax; 24 | @property (assign, nonatomic) CGFloat yMin; 25 | @property (strong, nonatomic) NSString *xTypeName; 26 | @property (strong, nonatomic) NSString *yTypeName; 27 | @property (strong, nonatomic) NSString *unit; 28 | 29 | @property (assign, nonatomic) CGFloat defaultSpace;//X轴点之间的间隔 30 | 31 | /** 32 | * 记录坐标轴的第一个frame 33 | */ 34 | @property (assign, nonatomic) CGRect firstFrame; 35 | @property (assign, nonatomic) CGRect firstStrFrame;//第一个点的文字的frame 36 | 37 | 38 | @end 39 | 40 | 41 | 42 | @implementation XAxisView 43 | 44 | - (id)initWithFrame:(CGRect)frame xTitleArray:(NSArray*)xTitleArray yValueArray:(NSArray*)yValueArray yMax:(CGFloat)yMax yMin:(CGFloat)yMin yTypeName:(NSString*)yTypeName xTypeName:(NSString*)xTypeName unit:(NSString*)unit { 45 | 46 | self = [super initWithFrame:frame]; 47 | if (self) { 48 | self.backgroundColor = [UIColor whiteColor]; 49 | self.xTitleArray = xTitleArray; 50 | self.yValueArray = yValueArray; 51 | self.yMax = yMax; 52 | self.yMin = yMin; 53 | self.xTypeName = xTypeName; 54 | self.yTypeName = yTypeName; 55 | self.unit = unit; 56 | 57 | if (xTitleArray.count > 600) { 58 | _defaultSpace = 5; 59 | } 60 | else if (xTitleArray.count > 400 && xTitleArray.count <= 600){ 61 | _defaultSpace = 10; 62 | } 63 | else if (xTitleArray.count > 200 && xTitleArray.count <= 400){ 64 | _defaultSpace = 20; 65 | } 66 | else if (xTitleArray.count > 100 && xTitleArray.count <= 200){ 67 | _defaultSpace = 30; 68 | } 69 | else if (xTitleArray.count > 10 && xTitleArray.count <= 100){ 70 | _defaultSpace = 40; 71 | } 72 | else { 73 | _defaultSpace = (wsScreenWidth-leftMargin)/xTitleArray.count; 74 | } 75 | 76 | 77 | self.pointGap = (wsScreenWidth-leftMargin)/xTitleArray.count; 78 | 79 | 80 | } 81 | 82 | return self; 83 | } 84 | 85 | - (void)setPointGap:(CGFloat)pointGap { 86 | _pointGap = pointGap; 87 | 88 | [self setNeedsDisplay]; 89 | } 90 | 91 | - (void)setIsLongPress:(BOOL)isLongPress { 92 | _isLongPress = isLongPress; 93 | 94 | [self setNeedsDisplay]; 95 | } 96 | 97 | - (void)drawRect:(CGRect)rect { 98 | [super drawRect:rect]; 99 | 100 | CGContextRef context = UIGraphicsGetCurrentContext(); 101 | 102 | [self drawShadow];//画渐变色背景 103 | 104 | ////////////////////// X轴文字 ////////////////////////// 105 | // 添加坐标轴Label 106 | for (int i = 0; i < self.xTitleArray.count; i++) { 107 | NSString *title = self.xTitleArray[i]; 108 | title = [title stringByReplacingOccurrencesOfString:@" " withString:@"\r\n"]; 109 | 110 | [[UIColor blackColor] set]; 111 | NSDictionary *attr = @{NSFontAttributeName : [UIFont systemFontOfSize:10]}; 112 | CGSize labelSize = [title sizeWithAttributes:attr]; 113 | 114 | CGRect titleRect = CGRectMake((i + 1) * self.pointGap - labelSize.width / 2,self.frame.size.height - labelSize.height,labelSize.width,labelSize.height); 115 | 116 | if (i == 0) { 117 | self.firstFrame = titleRect; 118 | if (titleRect.origin.x < 0) { 119 | titleRect.origin.x = 0; 120 | } 121 | 122 | [title drawInRect:titleRect withAttributes:@{NSFontAttributeName :[UIFont systemFontOfSize:10],NSForegroundColorAttributeName:kChartTextColor}]; 123 | 124 | //画垂直X轴的竖线 125 | [self drawLine:context 126 | startPoint:CGPointMake(titleRect.origin.x+labelSize.width/2, self.frame.size.height - labelSize.height-5) 127 | endPoint:CGPointMake(titleRect.origin.x+labelSize.width/2, self.frame.size.height - labelSize.height-10) 128 | lineColor:kChartLineColor 129 | lineWidth:1]; 130 | } 131 | // 如果Label的文字有重叠,那么不绘制 132 | CGFloat maxX = CGRectGetMaxX(self.firstFrame); 133 | if (i != 0) { 134 | if ((maxX + 5) > titleRect.origin.x) { 135 | //不绘制 136 | 137 | }else{ 138 | 139 | [title drawInRect:titleRect withAttributes:@{NSFontAttributeName :[UIFont systemFontOfSize:10],NSForegroundColorAttributeName:kChartTextColor}]; 140 | //画垂直X轴的竖线 141 | [self drawLine:context 142 | startPoint:CGPointMake(titleRect.origin.x+labelSize.width/2, self.frame.size.height - labelSize.height-5) 143 | endPoint:CGPointMake(titleRect.origin.x+labelSize.width/2, self.frame.size.height - labelSize.height-10) 144 | lineColor:kChartLineColor 145 | lineWidth:1]; 146 | 147 | self.firstFrame = titleRect; 148 | } 149 | }else { 150 | if (self.firstFrame.origin.x < 0) { 151 | 152 | CGRect frame = self.firstFrame; 153 | frame.origin.x = 0; 154 | self.firstFrame = frame; 155 | } 156 | } 157 | 158 | } 159 | 160 | //////////////// 画原点上的x轴 /////////////////////// 161 | NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:10]}; 162 | CGSize textSize = [@"22-22\r\n22:22" sizeWithAttributes:attribute]; 163 | 164 | [self drawLine:context 165 | startPoint:CGPointMake(0, self.frame.size.height - textSize.height - 5) 166 | endPoint:CGPointMake(self.frame.size.width, self.frame.size.height - textSize.height - 5) 167 | lineColor:kChartLineColor 168 | lineWidth:1]; 169 | 170 | 171 | //////////////// 画横向分割线 /////////////////////// 172 | CGFloat separateMargin = (self.frame.size.height - topMargin - textSize.height - 5 - 5 * 1) / 5; 173 | for (int i = 0; i < 5; i++) { 174 | 175 | [self drawLine:context 176 | startPoint:CGPointMake(0, self.frame.size.height - textSize.height - 5 - (i + 1) *(separateMargin + 1)) 177 | endPoint:CGPointMake(self.frame.size.width, self.frame.size.height - textSize.height - 5 - (i + 1) *(separateMargin + 1)) 178 | lineColor:[UIColor lightGrayColor] 179 | lineWidth:.3]; 180 | } 181 | 182 | 183 | /////////////////////// 根据数据源画折线 ///////////////////////// 184 | if (self.yValueArray && self.yValueArray.count > 0) { 185 | 186 | //画折线 187 | for (NSInteger i = 0; i < self.yValueArray.count; i++) { 188 | 189 | //如果是最后一个点 190 | if (i == self.yValueArray.count-1) { 191 | 192 | NSNumber *endValue = self.yValueArray[i]; 193 | CGFloat chartHeight = self.frame.size.height - textSize.height - 5 - topMargin; 194 | CGPoint endPoint = CGPointMake((i+1)*self.pointGap, chartHeight - (endValue.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 195 | 196 | //画最后一个点 197 | UIColor*aColor = pointColor; //点的颜色 198 | CGContextSetFillColorWithColor(context, aColor.CGColor);//填充颜色 199 | CGContextAddArc(context, endPoint.x, endPoint.y, 1, 0, 2*M_PI, 0); //添加一个圆 200 | CGContextDrawPath(context, kCGPathFill);//绘制填充 201 | 202 | 203 | //画点上的文字 204 | NSString *str = [self removeZeroInFloatString:[NSString stringWithFormat:@"%@",endValue]]; 205 | 206 | 207 | NSDictionary *attr = @{NSFontAttributeName : [UIFont systemFontOfSize:10]}; 208 | CGSize strSize = [str sizeWithAttributes:attr]; 209 | 210 | CGRect strRect = CGRectMake(endPoint.x-strSize.width/2,endPoint.y-strSize.height,strSize.width,strSize.height); 211 | 212 | // 如果点的文字有重叠,那么不绘制 213 | CGFloat maxX = CGRectGetMaxX(self.firstStrFrame); 214 | if (i != 0) { 215 | if ((maxX + 6) > strRect.origin.x) { 216 | //不绘制 217 | 218 | }else{ 219 | [str drawInRect:strRect withAttributes:@{NSFontAttributeName :[UIFont systemFontOfSize:10],NSForegroundColorAttributeName:kChartTextColor}]; 220 | 221 | self.firstStrFrame = strRect; 222 | } 223 | }else { 224 | if (self.firstStrFrame.origin.x < 0) { 225 | 226 | CGRect frame = self.firstStrFrame; 227 | frame.origin.x = 0; 228 | self.firstStrFrame = frame; 229 | } 230 | } 231 | 232 | }else { 233 | 234 | NSNumber *startValue = self.yValueArray[i]; 235 | NSNumber *endValue = self.yValueArray[i+1]; 236 | CGFloat chartHeight = self.frame.size.height - textSize.height - 5 - topMargin; 237 | 238 | CGPoint startPoint = CGPointMake((i+1)*self.pointGap, chartHeight - (startValue.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 239 | CGPoint endPoint = CGPointMake((i+2)*self.pointGap, chartHeight - (endValue.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 240 | 241 | CGFloat normal[1]={1}; 242 | CGContextSetLineDash(context,0,normal,0); //画实线 243 | 244 | [self drawLine:context startPoint:startPoint endPoint:endPoint lineColor:[UIColor colorWithRed:26/255.0 green:135/255.0 blue:254/255.0 alpha:1] lineWidth:1]; 245 | 246 | 247 | //画点 248 | UIColor*aColor = pointColor; //点的颜色 249 | CGContextSetFillColorWithColor(context, aColor.CGColor);//填充颜色 250 | CGContextAddArc(context, startPoint.x, startPoint.y, 1, 0, 2*M_PI, 0); //添加一个圆 251 | CGContextDrawPath(context, kCGPathFill);//绘制填充 252 | 253 | 254 | if (!_isShowLabel) { 255 | 256 | //画点上的文字 257 | NSString *str = [self removeZeroInFloatString:[NSString stringWithFormat:@"%@",startValue]]; 258 | 259 | 260 | NSDictionary *attr = @{NSFontAttributeName : [UIFont systemFontOfSize:10]}; 261 | CGSize strSize = [str sizeWithAttributes:attr]; 262 | 263 | CGRect strRect = CGRectMake(startPoint.x-strSize.width/2,startPoint.y-strSize.height,strSize.width,strSize.height); 264 | if (i == 0) { 265 | self.firstStrFrame = strRect; 266 | if (strRect.origin.x < 0) { 267 | strRect.origin.x = 0; 268 | } 269 | 270 | [str drawInRect:strRect withAttributes:@{NSFontAttributeName :[UIFont systemFontOfSize:10],NSForegroundColorAttributeName:kChartTextColor}]; 271 | } 272 | // 如果点的文字有重叠,那么不绘制 273 | CGFloat maxX = CGRectGetMaxX(self.firstStrFrame); 274 | if (i != 0) { 275 | if ((maxX + 6) > strRect.origin.x) { 276 | 277 | }else{ 278 | 279 | [str drawInRect:strRect withAttributes:@{NSFontAttributeName :[UIFont systemFontOfSize:10],NSForegroundColorAttributeName:kChartTextColor}]; 280 | 281 | self.firstStrFrame = strRect; 282 | } 283 | }else { 284 | if (self.firstStrFrame.origin.x < 0) { 285 | 286 | CGRect frame = self.firstStrFrame; 287 | frame.origin.x = 0; 288 | self.firstStrFrame = frame; 289 | } 290 | } 291 | } 292 | } 293 | 294 | 295 | } 296 | } 297 | 298 | 299 | //长按时进入 300 | if(self.isLongPress) 301 | { 302 | int nowPoint = _currentLoc.x/self.pointGap; 303 | if(nowPoint >= 0 && nowPoint < [self.yValueArray count]) { 304 | 305 | NSNumber *num = [self.yValueArray objectAtIndex:nowPoint]; 306 | CGFloat chartHeight = self.frame.size.height - textSize.height - 5 - topMargin; 307 | 308 | CGPoint selectPoint = CGPointMake((nowPoint+1)*self.pointGap, chartHeight - (num.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 309 | 310 | 311 | CGContextSaveGState(context); 312 | 313 | 314 | //计算文字最大长度,以便于设置背景宽度 315 | CGFloat timeWidth = [[NSString stringWithFormat:@"%@:%@",self.xTypeName,self.xTitleArray[nowPoint]] sizeWithAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13],NSForegroundColorAttributeName:[UIColor whiteColor]}].width; 316 | CGFloat dataWidth = [[NSString stringWithFormat:@"%@:%@%@", self.yTypeName,[NSString stringWithFormat:@"%@",num],self.unit] sizeWithAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13],NSForegroundColorAttributeName:[UIColor whiteColor]}].width; 317 | CGFloat with = timeWidth > dataWidth ? timeWidth : dataWidth; 318 | CGFloat shadowWith = with+20; 319 | 320 | //画文字所在的位置 动态变化 321 | CGPoint drawPoint = CGPointZero; 322 | if(_screenLoc.x-shadowWith/2 > 0 && _screenLoc.x 323 | +shadowWith/2 < wsScreenWidth-leftMargin) { 324 | //如果按住的位置在屏幕靠右边边并且在屏幕靠上面的地方 那么字就显示在按住位置的左上角40 60位置 325 | drawPoint = CGPointMake(selectPoint.x-shadowWith/2, selectPoint.y-45); 326 | } 327 | else if(_screenLoc.x >((wsScreenWidth-leftMargin)/2)) { 328 | //如果按住的位置在屏幕靠右边边并且在屏幕靠上面的地方 那么字就显示在按住位置的左上角40 60位置 329 | drawPoint = CGPointMake(selectPoint.x-shadowWith-5, selectPoint.y-20); 330 | } 331 | else if (_screenLoc.x <= ((wsScreenWidth-leftMargin)/2)) { 332 | //如果按住的位置在屏幕靠左边边并且在屏幕靠上面的地方 那么字就显示在按住位置的右上角上角40 40位置 333 | drawPoint = CGPointMake(selectPoint.x+5, selectPoint.y-20); 334 | 335 | } 336 | 337 | //画竖线 338 | [self drawLine:context startPoint:CGPointMake(selectPoint.x, 0) endPoint:CGPointMake(selectPoint.x, self.frame.size.height- textSize.height - 5) lineColor:[UIColor lightGrayColor] lineWidth:1]; 339 | 340 | // 交界点 341 | CGRect myOval = {selectPoint.x-2, selectPoint.y-2, 4, 4}; 342 | CGContextSetFillColorWithColor(context, [UIColor orangeColor].CGColor); 343 | CGContextAddEllipseInRect(context, myOval); 344 | CGContextFillPath(context); 345 | 346 | 347 | //设置数据背景,放在竖线之后加载,不会被竖线遮住 348 | CGContextSetFillColorWithColor(context, wsRGBA(1, 0, 0, 0.5).CGColor); 349 | CGPathRef clippath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(drawPoint.x, drawPoint.y, with+20, 40) cornerRadius:10].CGPath; 350 | CGContextAddPath(context, clippath); 351 | CGContextClosePath(context); 352 | CGContextDrawPath(context, kCGPathFill); 353 | 354 | [[NSString stringWithFormat:@"%@:%@",self.xTypeName,self.xTitleArray[nowPoint]] drawInRect:CGRectMake(drawPoint.x+10, drawPoint.y+5, with, 15) withAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13],NSForegroundColorAttributeName:[UIColor whiteColor]}]; 355 | [[NSString stringWithFormat:@"%@:%@%@", self.yTypeName,[NSString stringWithFormat:@"%@",num],self.unit] drawInRect:CGRectMake(drawPoint.x+10, drawPoint.y+20, with, 15) withAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13],NSForegroundColorAttributeName:[UIColor whiteColor]}]; 356 | 357 | 358 | 359 | } 360 | } 361 | 362 | 363 | 364 | } 365 | 366 | - (void)drawShadow { 367 | CGContextRef context = UIGraphicsGetCurrentContext(); 368 | CGMutablePathRef path = CGPathCreateMutable(); 369 | NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:10]}; 370 | CGSize textSize = [@"22-22\r\n22:22" sizeWithAttributes:attribute]; 371 | 372 | CGPathMoveToPoint(path, NULL, self.pointGap, self.frame.size.height - textSize.height-5); 373 | NSNumber *startValue = self.yValueArray[0]; 374 | CGFloat chartHeight = self.frame.size.height - textSize.height - 5 - topMargin; 375 | CGPoint firstStartPoint = CGPointMake(self.pointGap, chartHeight - (startValue.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 376 | CGPathAddCurveToPoint(path, NULL,(self.pointGap+firstStartPoint.x)/2, self.pointGap, (self.pointGap+firstStartPoint.x)/2, firstStartPoint.y, firstStartPoint.x, firstStartPoint.y); 377 | 378 | 379 | //画折线 380 | for (NSInteger i = 0; i < self.yValueArray.count; i++) { 381 | CGFloat chartHeight = self.frame.size.height - textSize.height - 5 - topMargin; 382 | NSNumber *startValue = self.yValueArray[i]; 383 | CGPoint startPoint = CGPointMake((i+1)*self.pointGap, chartHeight - (startValue.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 384 | 385 | if (i == self.yValueArray.count-1) { 386 | CGPathAddLineToPoint(path, NULL, startPoint.x,startPoint.y); 387 | } 388 | else { 389 | NSNumber *endValue = self.yValueArray[i+1]; 390 | CGPoint endPoint = CGPointMake((i+2)*self.pointGap, chartHeight - (endValue.floatValue-self.yMin)/(self.yMax-self.yMin) * chartHeight+topMargin); 391 | 392 | CGPathAddCurveToPoint(path, NULL,(startPoint.x+endPoint.x)/2, startPoint.y, (startPoint.x+endPoint.x)/2, endPoint.y, endPoint.x, endPoint.y); 393 | } 394 | 395 | } 396 | 397 | CGPathAddLineToPoint(path, NULL, self.pointGap*self.yValueArray.count, self.frame.size.height - textSize.height-5); 398 | CGPathCloseSubpath(path); 399 | //绘制渐变 400 | [self drawLinearGradient:context path:path startColor:[UIColor colorWithRed:26/255.0 green:135/255.0 blue:254/255.0 alpha:1].CGColor endColor:[UIColor whiteColor].CGColor]; 401 | //注意释放CGMutablePathRef 402 | CGPathRelease(path); 403 | } 404 | 405 | 406 | - (void)drawLine:(CGContextRef)context startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint lineColor:(UIColor *)lineColor lineWidth:(CGFloat)width { 407 | 408 | CGContextSetShouldAntialias(context, YES ); //抗锯齿 409 | CGColorSpaceRef Linecolorspace1 = CGColorSpaceCreateDeviceRGB(); 410 | CGContextSetStrokeColorSpace(context, Linecolorspace1); 411 | CGContextSetLineWidth(context, width); 412 | CGContextSetStrokeColorWithColor(context, lineColor.CGColor); 413 | CGContextMoveToPoint(context, startPoint.x, startPoint.y); 414 | // CGContextAddLineToPoint(context, endPoint.x, endPoint.y); 415 | CGContextAddCurveToPoint(context, (startPoint.x+endPoint.x)/2, startPoint.y, (startPoint.x+endPoint.x)/2, endPoint.y, endPoint.x, endPoint.y); 416 | CGContextStrokePath(context); 417 | CGColorSpaceRelease(Linecolorspace1); 418 | 419 | } 420 | 421 | 422 | - (void)drawLinearGradient:(CGContextRef)context path:(CGPathRef)path startColor:(CGColorRef)startColor endColor:(CGColorRef)endColor{ 423 | 424 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 425 | CGFloat locations[] = { 0.0, 1.0 }; 426 | NSArray *colors = @[(__bridge id) startColor, (__bridge id) endColor]; 427 | CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colors, locations); 428 | CGRect pathRect = CGPathGetBoundingBox(path); 429 | //具体方向可根据需求修改 430 | CGPoint startPoint = CGPointMake(CGRectGetMidX(pathRect), CGRectGetMinY(pathRect)); 431 | CGPoint endPoint = CGPointMake(CGRectGetMidX(pathRect), CGRectGetMaxY(pathRect)); 432 | CGContextSaveGState(context); 433 | CGContextAddPath(context, path); 434 | CGContextClip(context); 435 | CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 436 | CGContextRestoreGState(context); 437 | CGGradientRelease(gradient); 438 | CGColorSpaceRelease(colorSpace); 439 | } 440 | 441 | //去掉小数点之后的无效0; 442 | -(NSString*)removeZeroInFloatString:(NSString*)floatString { 443 | NSString *outNumber = [NSString stringWithFormat:@"%@",@(floatString.longLongValue)]; 444 | return outNumber; 445 | } 446 | 447 | @end 448 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/YAxisView.h: -------------------------------------------------------------------------------- 1 | // 2 | // yAxisView.h 3 | // 3333 4 | // 5 | // Created by iMac on 16/11/10. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YAxisView : UIView 12 | 13 | 14 | - (id)initWithFrame:(CGRect)frame yMax:(CGFloat)yMax yMin:(CGFloat)yMin; 15 | 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/WSLineChartView/YAxisView.m: -------------------------------------------------------------------------------- 1 | // 2 | // yAxisView.m 3 | // 3333 4 | // 5 | // Created by iMac on 16/11/10. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import "YAxisView.h" 10 | #define topMargin 50 // 为顶部留出的空白 11 | #define xAxisTextGap 5 //x轴文字与坐标轴间隙 12 | #define numberOfYAxisElements 5 // y轴分为几段 13 | #define kChartLineColor [UIColor grayColor] 14 | #define kChartTextColor [UIColor blackColor] 15 | 16 | 17 | @implementation YAxisView 18 | 19 | - (id)initWithFrame:(CGRect)frame yMax:(CGFloat)yMax yMin:(CGFloat)yMin { 20 | 21 | if (self = [super initWithFrame:frame]) { 22 | self.backgroundColor = [UIColor whiteColor]; 23 | 24 | // 计算坐标轴的位置以及大小 25 | NSDictionary *attr = @{NSFontAttributeName : [UIFont systemFontOfSize:10]}; 26 | CGSize labelSize = [@"22-22\r\n22:22" sizeWithAttributes:attr]; 27 | // 垂直坐标轴 28 | UIView *separate = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width-1, 0, 1, self.frame.size.height - labelSize.height - xAxisTextGap)]; 29 | separate.backgroundColor = kChartLineColor; 30 | [self addSubview:separate]; 31 | 32 | 33 | // Label做占据的高度 34 | CGFloat allLabelHeight = self.frame.size.height - xAxisTextGap - labelSize.height; 35 | // Label之间的间隙 36 | CGFloat labelMargin = (allLabelHeight - topMargin) / numberOfYAxisElements; 37 | 38 | // 添加Label 39 | for (int i = 0; i < numberOfYAxisElements + 1; i++) { 40 | UILabel *label = [[UILabel alloc] init]; 41 | double avgValue = (yMax - yMin) / numberOfYAxisElements; 42 | 43 | double value = yMin + avgValue * i; 44 | 45 | if (value >= 1000000) { 46 | label.text = [NSString stringWithFormat:@"%.0f万", value/10000.0]; 47 | } 48 | else { 49 | // 判断是不是小数 50 | if ([self isPureFloat:value]) { 51 | label.text = [NSString stringWithFormat:@"%.2f", value]; 52 | } 53 | else { 54 | label.text = [NSString stringWithFormat:@"%.0f", value]; 55 | } 56 | } 57 | 58 | label.textAlignment = NSTextAlignmentRight;// UITextAlignmentRight; 59 | label.font = [UIFont systemFontOfSize:10]; 60 | label.textColor = kChartTextColor; 61 | label.frame = CGRectMake(0, allLabelHeight - labelMargin* i - labelSize.height/2, self.frame.size.width - 1 - 5, labelSize.height); 62 | 63 | [self addSubview:label]; 64 | } 65 | 66 | 67 | 68 | } 69 | return self; 70 | } 71 | 72 | // 判断是小数还是整数 73 | - (BOOL)isPureFloat:(double)num 74 | { 75 | int i = num; 76 | 77 | double result = num - i; 78 | 79 | // 当不等于0时,是小数 80 | return result != 0; 81 | } 82 | 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /WSLineChart/WSLineChart/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WSLineChart 4 | // 5 | // Created by iMac on 16/11/14. 6 | // Copyright © 2016年 zws. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | --------------------------------------------------------------------------------