├── README.md └── refreshDemo ├── refreshDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── refreshDemo.xccheckout └── xcuserdata │ └── ios_zhaoxiao.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── refreshDemo.xcscheme │ └── xcschememanagement.plist ├── refreshDemo ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── ViewController.h ├── ViewController.m ├── arrow@2x.png ├── main.m └── refreshBG.png ├── refreshDemoTests ├── Info.plist └── refreshDemoTests.m └── refreshView ├── UIScrollView+ZSDRefresh.h ├── UIScrollView+ZSDRefresh.m ├── ZSDRefreshBaseView.h ├── ZSDRefreshBaseView.m ├── ZSDRefreshCircleView.h ├── ZSDRefreshCircleView.m ├── ZSDRefreshFootView.h ├── ZSDRefreshFootView.m ├── ZSDRefreshHeadView.h └── ZSDRefreshHeadView.m /README.md: -------------------------------------------------------------------------------- 1 | # ZSDRefreshView 2 | 类似淘宝的下拉刷新控件 3 | ============================= 4 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F0D2DE9B1AB042130006EEC7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DE9A1AB042130006EEC7 /* main.m */; }; 11 | F0D2DE9E1AB042130006EEC7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DE9D1AB042130006EEC7 /* AppDelegate.m */; }; 12 | F0D2DEA11AB042130006EEC7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DEA01AB042130006EEC7 /* ViewController.m */; }; 13 | F0D2DEA41AB042130006EEC7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F0D2DEA21AB042130006EEC7 /* Main.storyboard */; }; 14 | F0D2DEA61AB042130006EEC7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F0D2DEA51AB042130006EEC7 /* Images.xcassets */; }; 15 | F0D2DEA91AB042130006EEC7 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0D2DEA71AB042130006EEC7 /* LaunchScreen.xib */; }; 16 | F0D2DEB51AB042140006EEC7 /* refreshDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DEB41AB042140006EEC7 /* refreshDemoTests.m */; }; 17 | F0D2DEC71AB042310006EEC7 /* UIScrollView+ZSDRefresh.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DEC01AB042310006EEC7 /* UIScrollView+ZSDRefresh.m */; }; 18 | F0D2DEC81AB042310006EEC7 /* ZSDRefreshBaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DEC21AB042310006EEC7 /* ZSDRefreshBaseView.m */; }; 19 | F0D2DEC91AB042310006EEC7 /* ZSDRefreshCircleView.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DEC41AB042310006EEC7 /* ZSDRefreshCircleView.m */; }; 20 | F0D2DECA1AB042310006EEC7 /* ZSDRefreshHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = F0D2DEC61AB042310006EEC7 /* ZSDRefreshHeadView.m */; }; 21 | F0D2DECD1AB043880006EEC7 /* arrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0D2DECB1AB043880006EEC7 /* arrow@2x.png */; }; 22 | F0D2DECE1AB043880006EEC7 /* refreshBG.png in Resources */ = {isa = PBXBuildFile; fileRef = F0D2DECC1AB043880006EEC7 /* refreshBG.png */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | F0D2DEAF1AB042140006EEC7 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = F0D2DE8D1AB042130006EEC7 /* Project object */; 29 | proxyType = 1; 30 | remoteGlobalIDString = F0D2DE941AB042130006EEC7; 31 | remoteInfo = refreshDemo; 32 | }; 33 | /* End PBXContainerItemProxy section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | F0D2DE951AB042130006EEC7 /* refreshDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = refreshDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | F0D2DE991AB042130006EEC7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | F0D2DE9A1AB042130006EEC7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 39 | F0D2DE9C1AB042130006EEC7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 40 | F0D2DE9D1AB042130006EEC7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 41 | F0D2DE9F1AB042130006EEC7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 42 | F0D2DEA01AB042130006EEC7 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 43 | F0D2DEA31AB042130006EEC7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | F0D2DEA51AB042130006EEC7 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 45 | F0D2DEA81AB042130006EEC7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 46 | F0D2DEAE1AB042140006EEC7 /* refreshDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = refreshDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | F0D2DEB31AB042140006EEC7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | F0D2DEB41AB042140006EEC7 /* refreshDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = refreshDemoTests.m; sourceTree = ""; }; 49 | F0D2DEBF1AB042310006EEC7 /* UIScrollView+ZSDRefresh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+ZSDRefresh.h"; sourceTree = ""; }; 50 | F0D2DEC01AB042310006EEC7 /* UIScrollView+ZSDRefresh.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+ZSDRefresh.m"; sourceTree = ""; }; 51 | F0D2DEC11AB042310006EEC7 /* ZSDRefreshBaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZSDRefreshBaseView.h; sourceTree = ""; }; 52 | F0D2DEC21AB042310006EEC7 /* ZSDRefreshBaseView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZSDRefreshBaseView.m; sourceTree = ""; }; 53 | F0D2DEC31AB042310006EEC7 /* ZSDRefreshCircleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZSDRefreshCircleView.h; sourceTree = ""; }; 54 | F0D2DEC41AB042310006EEC7 /* ZSDRefreshCircleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZSDRefreshCircleView.m; sourceTree = ""; }; 55 | F0D2DEC51AB042310006EEC7 /* ZSDRefreshHeadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZSDRefreshHeadView.h; sourceTree = ""; }; 56 | F0D2DEC61AB042310006EEC7 /* ZSDRefreshHeadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZSDRefreshHeadView.m; sourceTree = ""; }; 57 | F0D2DECB1AB043880006EEC7 /* arrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "arrow@2x.png"; sourceTree = ""; }; 58 | F0D2DECC1AB043880006EEC7 /* refreshBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = refreshBG.png; sourceTree = ""; }; 59 | /* End PBXFileReference section */ 60 | 61 | /* Begin PBXFrameworksBuildPhase section */ 62 | F0D2DE921AB042130006EEC7 /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | F0D2DEAB1AB042140006EEC7 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | F0D2DE8C1AB042130006EEC7 = { 80 | isa = PBXGroup; 81 | children = ( 82 | F0D2DE971AB042130006EEC7 /* refreshDemo */, 83 | F0D2DEB11AB042140006EEC7 /* refreshDemoTests */, 84 | F0D2DE961AB042130006EEC7 /* Products */, 85 | ); 86 | sourceTree = ""; 87 | }; 88 | F0D2DE961AB042130006EEC7 /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | F0D2DE951AB042130006EEC7 /* refreshDemo.app */, 92 | F0D2DEAE1AB042140006EEC7 /* refreshDemoTests.xctest */, 93 | ); 94 | name = Products; 95 | sourceTree = ""; 96 | }; 97 | F0D2DE971AB042130006EEC7 /* refreshDemo */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | F0D2DEBE1AB042310006EEC7 /* refreshView */, 101 | F0D2DE9C1AB042130006EEC7 /* AppDelegate.h */, 102 | F0D2DE9D1AB042130006EEC7 /* AppDelegate.m */, 103 | F0D2DE9F1AB042130006EEC7 /* ViewController.h */, 104 | F0D2DEA01AB042130006EEC7 /* ViewController.m */, 105 | F0D2DEA21AB042130006EEC7 /* Main.storyboard */, 106 | F0D2DEA51AB042130006EEC7 /* Images.xcassets */, 107 | F0D2DEA71AB042130006EEC7 /* LaunchScreen.xib */, 108 | F0D2DE981AB042130006EEC7 /* Supporting Files */, 109 | ); 110 | path = refreshDemo; 111 | sourceTree = ""; 112 | }; 113 | F0D2DE981AB042130006EEC7 /* Supporting Files */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | F0D2DECB1AB043880006EEC7 /* arrow@2x.png */, 117 | F0D2DECC1AB043880006EEC7 /* refreshBG.png */, 118 | F0D2DE991AB042130006EEC7 /* Info.plist */, 119 | F0D2DE9A1AB042130006EEC7 /* main.m */, 120 | ); 121 | name = "Supporting Files"; 122 | sourceTree = ""; 123 | }; 124 | F0D2DEB11AB042140006EEC7 /* refreshDemoTests */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | F0D2DEB41AB042140006EEC7 /* refreshDemoTests.m */, 128 | F0D2DEB21AB042140006EEC7 /* Supporting Files */, 129 | ); 130 | path = refreshDemoTests; 131 | sourceTree = ""; 132 | }; 133 | F0D2DEB21AB042140006EEC7 /* Supporting Files */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | F0D2DEB31AB042140006EEC7 /* Info.plist */, 137 | ); 138 | name = "Supporting Files"; 139 | sourceTree = ""; 140 | }; 141 | F0D2DEBE1AB042310006EEC7 /* refreshView */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | F0D2DEBF1AB042310006EEC7 /* UIScrollView+ZSDRefresh.h */, 145 | F0D2DEC01AB042310006EEC7 /* UIScrollView+ZSDRefresh.m */, 146 | F0D2DEC11AB042310006EEC7 /* ZSDRefreshBaseView.h */, 147 | F0D2DEC21AB042310006EEC7 /* ZSDRefreshBaseView.m */, 148 | F0D2DEC31AB042310006EEC7 /* ZSDRefreshCircleView.h */, 149 | F0D2DEC41AB042310006EEC7 /* ZSDRefreshCircleView.m */, 150 | F0D2DEC51AB042310006EEC7 /* ZSDRefreshHeadView.h */, 151 | F0D2DEC61AB042310006EEC7 /* ZSDRefreshHeadView.m */, 152 | ); 153 | path = refreshView; 154 | sourceTree = SOURCE_ROOT; 155 | }; 156 | /* End PBXGroup section */ 157 | 158 | /* Begin PBXNativeTarget section */ 159 | F0D2DE941AB042130006EEC7 /* refreshDemo */ = { 160 | isa = PBXNativeTarget; 161 | buildConfigurationList = F0D2DEB81AB042140006EEC7 /* Build configuration list for PBXNativeTarget "refreshDemo" */; 162 | buildPhases = ( 163 | F0D2DE911AB042130006EEC7 /* Sources */, 164 | F0D2DE921AB042130006EEC7 /* Frameworks */, 165 | F0D2DE931AB042130006EEC7 /* Resources */, 166 | ); 167 | buildRules = ( 168 | ); 169 | dependencies = ( 170 | ); 171 | name = refreshDemo; 172 | productName = refreshDemo; 173 | productReference = F0D2DE951AB042130006EEC7 /* refreshDemo.app */; 174 | productType = "com.apple.product-type.application"; 175 | }; 176 | F0D2DEAD1AB042140006EEC7 /* refreshDemoTests */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = F0D2DEBB1AB042140006EEC7 /* Build configuration list for PBXNativeTarget "refreshDemoTests" */; 179 | buildPhases = ( 180 | F0D2DEAA1AB042140006EEC7 /* Sources */, 181 | F0D2DEAB1AB042140006EEC7 /* Frameworks */, 182 | F0D2DEAC1AB042140006EEC7 /* Resources */, 183 | ); 184 | buildRules = ( 185 | ); 186 | dependencies = ( 187 | F0D2DEB01AB042140006EEC7 /* PBXTargetDependency */, 188 | ); 189 | name = refreshDemoTests; 190 | productName = refreshDemoTests; 191 | productReference = F0D2DEAE1AB042140006EEC7 /* refreshDemoTests.xctest */; 192 | productType = "com.apple.product-type.bundle.unit-test"; 193 | }; 194 | /* End PBXNativeTarget section */ 195 | 196 | /* Begin PBXProject section */ 197 | F0D2DE8D1AB042130006EEC7 /* Project object */ = { 198 | isa = PBXProject; 199 | attributes = { 200 | LastUpgradeCheck = 0610; 201 | ORGANIZATIONNAME = shaw; 202 | TargetAttributes = { 203 | F0D2DE941AB042130006EEC7 = { 204 | CreatedOnToolsVersion = 6.1; 205 | }; 206 | F0D2DEAD1AB042140006EEC7 = { 207 | CreatedOnToolsVersion = 6.1; 208 | TestTargetID = F0D2DE941AB042130006EEC7; 209 | }; 210 | }; 211 | }; 212 | buildConfigurationList = F0D2DE901AB042130006EEC7 /* Build configuration list for PBXProject "refreshDemo" */; 213 | compatibilityVersion = "Xcode 3.2"; 214 | developmentRegion = English; 215 | hasScannedForEncodings = 0; 216 | knownRegions = ( 217 | en, 218 | Base, 219 | ); 220 | mainGroup = F0D2DE8C1AB042130006EEC7; 221 | productRefGroup = F0D2DE961AB042130006EEC7 /* Products */; 222 | projectDirPath = ""; 223 | projectRoot = ""; 224 | targets = ( 225 | F0D2DE941AB042130006EEC7 /* refreshDemo */, 226 | F0D2DEAD1AB042140006EEC7 /* refreshDemoTests */, 227 | ); 228 | }; 229 | /* End PBXProject section */ 230 | 231 | /* Begin PBXResourcesBuildPhase section */ 232 | F0D2DE931AB042130006EEC7 /* Resources */ = { 233 | isa = PBXResourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | F0D2DECD1AB043880006EEC7 /* arrow@2x.png in Resources */, 237 | F0D2DEA41AB042130006EEC7 /* Main.storyboard in Resources */, 238 | F0D2DEA91AB042130006EEC7 /* LaunchScreen.xib in Resources */, 239 | F0D2DECE1AB043880006EEC7 /* refreshBG.png in Resources */, 240 | F0D2DEA61AB042130006EEC7 /* Images.xcassets in Resources */, 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | F0D2DEAC1AB042140006EEC7 /* Resources */ = { 245 | isa = PBXResourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXResourcesBuildPhase section */ 252 | 253 | /* Begin PBXSourcesBuildPhase section */ 254 | F0D2DE911AB042130006EEC7 /* Sources */ = { 255 | isa = PBXSourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | F0D2DEC91AB042310006EEC7 /* ZSDRefreshCircleView.m in Sources */, 259 | F0D2DEA11AB042130006EEC7 /* ViewController.m in Sources */, 260 | F0D2DE9E1AB042130006EEC7 /* AppDelegate.m in Sources */, 261 | F0D2DECA1AB042310006EEC7 /* ZSDRefreshHeadView.m in Sources */, 262 | F0D2DE9B1AB042130006EEC7 /* main.m in Sources */, 263 | F0D2DEC71AB042310006EEC7 /* UIScrollView+ZSDRefresh.m in Sources */, 264 | F0D2DEC81AB042310006EEC7 /* ZSDRefreshBaseView.m in Sources */, 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | F0D2DEAA1AB042140006EEC7 /* Sources */ = { 269 | isa = PBXSourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | F0D2DEB51AB042140006EEC7 /* refreshDemoTests.m in Sources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXSourcesBuildPhase section */ 277 | 278 | /* Begin PBXTargetDependency section */ 279 | F0D2DEB01AB042140006EEC7 /* PBXTargetDependency */ = { 280 | isa = PBXTargetDependency; 281 | target = F0D2DE941AB042130006EEC7 /* refreshDemo */; 282 | targetProxy = F0D2DEAF1AB042140006EEC7 /* PBXContainerItemProxy */; 283 | }; 284 | /* End PBXTargetDependency section */ 285 | 286 | /* Begin PBXVariantGroup section */ 287 | F0D2DEA21AB042130006EEC7 /* Main.storyboard */ = { 288 | isa = PBXVariantGroup; 289 | children = ( 290 | F0D2DEA31AB042130006EEC7 /* Base */, 291 | ); 292 | name = Main.storyboard; 293 | sourceTree = ""; 294 | }; 295 | F0D2DEA71AB042130006EEC7 /* LaunchScreen.xib */ = { 296 | isa = PBXVariantGroup; 297 | children = ( 298 | F0D2DEA81AB042130006EEC7 /* Base */, 299 | ); 300 | name = LaunchScreen.xib; 301 | sourceTree = ""; 302 | }; 303 | /* End PBXVariantGroup section */ 304 | 305 | /* Begin XCBuildConfiguration section */ 306 | F0D2DEB61AB042140006EEC7 /* Debug */ = { 307 | isa = XCBuildConfiguration; 308 | buildSettings = { 309 | ALWAYS_SEARCH_USER_PATHS = NO; 310 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 311 | CLANG_CXX_LIBRARY = "libc++"; 312 | CLANG_ENABLE_MODULES = YES; 313 | CLANG_ENABLE_OBJC_ARC = YES; 314 | CLANG_WARN_BOOL_CONVERSION = YES; 315 | CLANG_WARN_CONSTANT_CONVERSION = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 321 | CLANG_WARN_UNREACHABLE_CODE = YES; 322 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 323 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 324 | COPY_PHASE_STRIP = NO; 325 | ENABLE_STRICT_OBJC_MSGSEND = YES; 326 | GCC_C_LANGUAGE_STANDARD = gnu99; 327 | GCC_DYNAMIC_NO_PIC = NO; 328 | GCC_OPTIMIZATION_LEVEL = 0; 329 | GCC_PREPROCESSOR_DEFINITIONS = ( 330 | "DEBUG=1", 331 | "$(inherited)", 332 | ); 333 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 341 | MTL_ENABLE_DEBUG_INFO = YES; 342 | ONLY_ACTIVE_ARCH = YES; 343 | SDKROOT = iphoneos; 344 | }; 345 | name = Debug; 346 | }; 347 | F0D2DEB71AB042140006EEC7 /* Release */ = { 348 | isa = XCBuildConfiguration; 349 | buildSettings = { 350 | ALWAYS_SEARCH_USER_PATHS = NO; 351 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 352 | CLANG_CXX_LIBRARY = "libc++"; 353 | CLANG_ENABLE_MODULES = YES; 354 | CLANG_ENABLE_OBJC_ARC = YES; 355 | CLANG_WARN_BOOL_CONVERSION = YES; 356 | CLANG_WARN_CONSTANT_CONVERSION = YES; 357 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 358 | CLANG_WARN_EMPTY_BODY = YES; 359 | CLANG_WARN_ENUM_CONVERSION = YES; 360 | CLANG_WARN_INT_CONVERSION = YES; 361 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 362 | CLANG_WARN_UNREACHABLE_CODE = YES; 363 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 364 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 365 | COPY_PHASE_STRIP = YES; 366 | ENABLE_NS_ASSERTIONS = NO; 367 | ENABLE_STRICT_OBJC_MSGSEND = YES; 368 | GCC_C_LANGUAGE_STANDARD = gnu99; 369 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 370 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 371 | GCC_WARN_UNDECLARED_SELECTOR = YES; 372 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 373 | GCC_WARN_UNUSED_FUNCTION = YES; 374 | GCC_WARN_UNUSED_VARIABLE = YES; 375 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 376 | MTL_ENABLE_DEBUG_INFO = NO; 377 | SDKROOT = iphoneos; 378 | VALIDATE_PRODUCT = YES; 379 | }; 380 | name = Release; 381 | }; 382 | F0D2DEB91AB042140006EEC7 /* Debug */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 386 | INFOPLIST_FILE = refreshDemo/Info.plist; 387 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | }; 390 | name = Debug; 391 | }; 392 | F0D2DEBA1AB042140006EEC7 /* Release */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 396 | INFOPLIST_FILE = refreshDemo/Info.plist; 397 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 398 | PRODUCT_NAME = "$(TARGET_NAME)"; 399 | }; 400 | name = Release; 401 | }; 402 | F0D2DEBC1AB042140006EEC7 /* Debug */ = { 403 | isa = XCBuildConfiguration; 404 | buildSettings = { 405 | BUNDLE_LOADER = "$(TEST_HOST)"; 406 | FRAMEWORK_SEARCH_PATHS = ( 407 | "$(SDKROOT)/Developer/Library/Frameworks", 408 | "$(inherited)", 409 | ); 410 | GCC_PREPROCESSOR_DEFINITIONS = ( 411 | "DEBUG=1", 412 | "$(inherited)", 413 | ); 414 | INFOPLIST_FILE = refreshDemoTests/Info.plist; 415 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/refreshDemo.app/refreshDemo"; 418 | }; 419 | name = Debug; 420 | }; 421 | F0D2DEBD1AB042140006EEC7 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | BUNDLE_LOADER = "$(TEST_HOST)"; 425 | FRAMEWORK_SEARCH_PATHS = ( 426 | "$(SDKROOT)/Developer/Library/Frameworks", 427 | "$(inherited)", 428 | ); 429 | INFOPLIST_FILE = refreshDemoTests/Info.plist; 430 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 431 | PRODUCT_NAME = "$(TARGET_NAME)"; 432 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/refreshDemo.app/refreshDemo"; 433 | }; 434 | name = Release; 435 | }; 436 | /* End XCBuildConfiguration section */ 437 | 438 | /* Begin XCConfigurationList section */ 439 | F0D2DE901AB042130006EEC7 /* Build configuration list for PBXProject "refreshDemo" */ = { 440 | isa = XCConfigurationList; 441 | buildConfigurations = ( 442 | F0D2DEB61AB042140006EEC7 /* Debug */, 443 | F0D2DEB71AB042140006EEC7 /* Release */, 444 | ); 445 | defaultConfigurationIsVisible = 0; 446 | defaultConfigurationName = Release; 447 | }; 448 | F0D2DEB81AB042140006EEC7 /* Build configuration list for PBXNativeTarget "refreshDemo" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | F0D2DEB91AB042140006EEC7 /* Debug */, 452 | F0D2DEBA1AB042140006EEC7 /* Release */, 453 | ); 454 | defaultConfigurationIsVisible = 0; 455 | }; 456 | F0D2DEBB1AB042140006EEC7 /* Build configuration list for PBXNativeTarget "refreshDemoTests" */ = { 457 | isa = XCConfigurationList; 458 | buildConfigurations = ( 459 | F0D2DEBC1AB042140006EEC7 /* Debug */, 460 | F0D2DEBD1AB042140006EEC7 /* Release */, 461 | ); 462 | defaultConfigurationIsVisible = 0; 463 | }; 464 | /* End XCConfigurationList section */ 465 | }; 466 | rootObject = F0D2DE8D1AB042130006EEC7 /* Project object */; 467 | } 468 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo.xcodeproj/project.xcworkspace/xcshareddata/refreshDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 0C404837-B3B9-4121-8C29-FCAD2A58CD69 9 | IDESourceControlProjectName 10 | refreshDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C6ED2762CAD7314BD71A93839850AD96A82CE997 14 | github.com:shaw2014/ZSDRefreshView.git 15 | 16 | IDESourceControlProjectPath 17 | refreshDemo/refreshDemo.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | C6ED2762CAD7314BD71A93839850AD96A82CE997 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:shaw2014/ZSDRefreshView.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | C6ED2762CAD7314BD71A93839850AD96A82CE997 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | C6ED2762CAD7314BD71A93839850AD96A82CE997 36 | IDESourceControlWCCName 37 | ZSDRefreshView 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo.xcodeproj/xcuserdata/ios_zhaoxiao.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo.xcodeproj/xcuserdata/ios_zhaoxiao.xcuserdatad/xcschemes/refreshDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo.xcodeproj/xcuserdata/ios_zhaoxiao.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | refreshDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | F0D2DE941AB042130006EEC7 16 | 17 | primary 18 | 19 | 20 | F0D2DEAD1AB042140006EEC7 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // refreshDemo 4 | // 5 | // Created by zhaoxiao on 15/3/11. 6 | // Copyright (c) 2015年 shaw. 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 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // refreshDemo 4 | // 5 | // Created by zhaoxiao on 15/3/11. 6 | // Copyright (c) 2015年 shaw. 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 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/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 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "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 | } -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.zsd.ios.$(PRODUCT_NAME:rfc1034identifier) 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 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // refreshDemo 4 | // 5 | // Created by zhaoxiao on 15/3/11. 6 | // Copyright (c) 2015年 shaw. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // refreshDemo 4 | // 5 | // Created by zhaoxiao on 15/3/11. 6 | // Copyright (c) 2015年 shaw. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "UIScrollView+ZSDRefresh.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | // Do any additional setup after loading the view, typically from a nib. 21 | 22 | self.view.backgroundColor = [UIColor grayColor]; 23 | 24 | UITableView *table = [[UITableView alloc]initWithFrame:CGRectMake(0, 50, self.view.bounds.size.width, self.view.bounds.size.height - 50) style:UITableViewStylePlain]; 25 | table.dataSource = self; 26 | table.delegate = self; 27 | [self.view addSubview:table]; 28 | 29 | __weak UITableView *weakTable = table; 30 | [table addHeaderWithCallback:^{ 31 | NSLog(@"refresh....."); 32 | 33 | double delayInSeconds = 2.f; 34 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 35 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 36 | [weakTable headerEndRefreshing]; 37 | }); 38 | }]; 39 | } 40 | 41 | #pragma mark -UITableViewDataSource 42 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 43 | { 44 | return 10; 45 | } 46 | 47 | -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 48 | { 49 | return 40; 50 | } 51 | 52 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 53 | { 54 | static NSString *identifier = @"Cell"; 55 | 56 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; 57 | if(!cell) 58 | { 59 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; 60 | } 61 | 62 | cell.textLabel.text = [NSString stringWithFormat:@"---------%ld",indexPath.row]; 63 | 64 | return cell; 65 | } 66 | 67 | - (void)didReceiveMemoryWarning { 68 | [super didReceiveMemoryWarning]; 69 | // Dispose of any resources that can be recreated. 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaw2014/ZSDRefreshView/36045e9b373e017987786480df9e6b4294fb74f0/refreshDemo/refreshDemo/arrow@2x.png -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // refreshDemo 4 | // 5 | // Created by zhaoxiao on 15/3/11. 6 | // Copyright (c) 2015年 shaw. 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 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemo/refreshBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shaw2014/ZSDRefreshView/36045e9b373e017987786480df9e6b4294fb74f0/refreshDemo/refreshDemo/refreshBG.png -------------------------------------------------------------------------------- /refreshDemo/refreshDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.zsd.ios.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /refreshDemo/refreshDemoTests/refreshDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // refreshDemoTests.m 3 | // refreshDemoTests 4 | // 5 | // Created by zhaoxiao on 15/3/11. 6 | // Copyright (c) 2015年 shaw. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface refreshDemoTests : XCTestCase 13 | 14 | @end 15 | 16 | @implementation refreshDemoTests 17 | 18 | - (void)setUp { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown { 24 | // Put teardown code here. This method is called after the invocation of each test method in the class. 25 | [super tearDown]; 26 | } 27 | 28 | - (void)testExample { 29 | // This is an example of a functional test case. 30 | XCTAssert(YES, @"Pass"); 31 | } 32 | 33 | - (void)testPerformanceExample { 34 | // This is an example of a performance test case. 35 | [self measureBlock:^{ 36 | // Put the code you want to measure the time of here. 37 | }]; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/UIScrollView+ZSDRefresh.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+ZSDRefresh.h 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/3/2. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIScrollView (ZSDRefresh) 12 | 13 | /** 14 | * 添加一个下拉刷新头部控件 15 | * 16 | * @param callback 回调 17 | */ 18 | - (void)addHeadWithCallback:(void (^)())callback; 19 | 20 | /** 21 | * 主动让下拉刷新头部控件进入刷新状态 22 | */ 23 | - (void)headBeginRefreshing; 24 | 25 | /** 26 | * 让下拉刷新头部控件停止刷新状态 27 | */ 28 | - (void)headEndRefreshing; 29 | 30 | /** 31 | * 是否正在下拉刷新 32 | */ 33 | @property (nonatomic, assign, readonly, getter = isHeadRefreshing) BOOL headRefreshing; 34 | 35 | /** 36 | * 添加一个上拉加载头部控件 37 | * 38 | * @param callback 回调 39 | */ 40 | - (void)addFootWithCallback:(void (^)())callback; 41 | 42 | /** 43 | * 主动让上拉加载头部控件进入刷新状态 44 | */ 45 | - (void)footBeginRefreshing; 46 | 47 | /** 48 | * 让上拉加载头部控件停止刷新状态 49 | */ 50 | - (void)footEndRefreshing; 51 | 52 | /** 53 | * 是否正在上拉刷新 54 | */ 55 | @property (nonatomic, assign, readonly, getter = isFootRefreshing) BOOL footRefreshing; 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/UIScrollView+ZSDRefresh.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+ZSDRefresh.m 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/3/2. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import "UIScrollView+ZSDRefresh.h" 10 | #import "ZSDRefreshHeadView.h" 11 | #import "ZSDRefreshFootView.h" 12 | #import 13 | 14 | @interface UIScrollView() 15 | 16 | @property (weak, nonatomic) ZSDRefreshHeadView *header; 17 | @property (weak, nonatomic) ZSDRefreshFootView *footer; 18 | 19 | @end 20 | 21 | @implementation UIScrollView (ZSDRefresh) 22 | 23 | #pragma mark - 运行时相关 24 | static char ZSDRefreshHeaderViewKey; 25 | static char ZSDRefreshFooterViewKey; 26 | 27 | - (void)setHeader:(ZSDRefreshHeadView *)header { 28 | [self willChangeValueForKey:@"ZSDRefreshHeaderViewKey"]; 29 | objc_setAssociatedObject(self, &ZSDRefreshHeaderViewKey, 30 | header, 31 | OBJC_ASSOCIATION_ASSIGN); 32 | [self didChangeValueForKey:@"ZSDRefreshHeaderViewKey"]; 33 | } 34 | 35 | - (ZSDRefreshHeadView *)header { 36 | return objc_getAssociatedObject(self, &ZSDRefreshHeaderViewKey); 37 | } 38 | 39 | - (void)setFooter:(ZSDRefreshFootView *)footer { 40 | [self willChangeValueForKey:@"ZSDRefreshFooterViewKey"]; 41 | objc_setAssociatedObject(self, &ZSDRefreshFooterViewKey, 42 | footer, 43 | OBJC_ASSOCIATION_ASSIGN); 44 | [self didChangeValueForKey:@"ZSDRefreshFooterViewKey"]; 45 | } 46 | 47 | - (ZSDRefreshHeadView *)footer { 48 | return objc_getAssociatedObject(self, &ZSDRefreshFooterViewKey); 49 | } 50 | 51 | /** 52 | * 添加一个下拉刷新头部控件 53 | * 54 | * @param callback 回调 55 | */ 56 | - (void)addHeadWithCallback:(void (^)())callback 57 | { 58 | // 1.创建新的header 59 | if (!self.header) { 60 | ZSDRefreshHeadView *header = [ZSDRefreshHeadView header]; 61 | [self addSubview:header]; 62 | self.header = header; 63 | } 64 | 65 | // 2.设置block回调 66 | self.header.beginRefreshCallback = callback; 67 | } 68 | 69 | /** 70 | * 主动让下拉刷新头部控件进入刷新状态 71 | */ 72 | - (void)headBeginRefreshing 73 | { 74 | [self.header beginRefresh]; 75 | } 76 | 77 | /** 78 | * 让下拉刷新头部控件停止刷新状态 79 | */ 80 | - (void)headEndRefreshing 81 | { 82 | [self.header endRefresh]; 83 | } 84 | 85 | - (BOOL)isHeadRefreshing 86 | { 87 | return self.header.state == ZSDRefreshStateRefreshing; 88 | } 89 | 90 | -(void)addFootWithCallback:(void (^)())callback 91 | { 92 | // 1.创建新的footer 93 | if (!self.footer) { 94 | ZSDRefreshFootView *footer = [ZSDRefreshFootView footer]; 95 | [self addSubview:footer]; 96 | self.footer = footer; 97 | } 98 | 99 | // 2.设置block回调 100 | self.footer.beginRefreshCallback = callback; 101 | } 102 | 103 | -(void)footBeginRefreshing 104 | { 105 | [self.footer beginRefresh]; 106 | } 107 | 108 | -(void)footEndRefreshing 109 | { 110 | [self.footer endRefresh]; 111 | } 112 | 113 | - (BOOL)isFootRefreshing 114 | { 115 | return self.footer.state == ZSDRefreshStateRefreshing; 116 | } 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshBaseView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshBaseView.h 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/2/28. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ZSDRefreshCircleView.h" 11 | 12 | #define kRefreshHeaderHeight 100.0f 13 | #define kRefreshFooterHeight 80.0f 14 | #define kOffsetObserveKey @"contentOffset" 15 | #define kContentSizeObserveKey @"contentSize" 16 | 17 | typedef NS_ENUM(NSInteger, ZSDRefreshState) 18 | { 19 | ZSDRefreshStateNone, 20 | ZSDRefreshStatePulling, // 松开就可以进行刷新的状态 21 | ZSDRefreshStateNormal, // 普通状态 22 | ZSDRefreshStateRefreshing, // 正在刷新中的状态 23 | ZSDRefreshStateWillRefreshing 24 | }; 25 | 26 | @interface ZSDRefreshBaseView : UIView 27 | 28 | @property (nonatomic,strong,readonly) UILabel *textLabel; 29 | @property (nonatomic,strong,readonly) UIImageView *backgroundImageView; 30 | @property (nonatomic,strong,readonly) ZSDRefreshCircleView *arrowCircleView; 31 | 32 | @property (nonatomic,weak,readonly) UIScrollView *scrollView; 33 | @property (nonatomic,assign,readonly) UIEdgeInsets scrollViewOriginalInset; 34 | 35 | @property (nonatomic,assign) ZSDRefreshState state; 36 | @property (nonatomic,assign) BOOL isInitFooter; 37 | 38 | @property (nonatomic,copy) void (^beginRefreshCallback)(); 39 | 40 | - (void)settingLabelText; 41 | 42 | -(void)beginRefresh; 43 | -(void)endRefresh; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshBaseView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshBaseView.m 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/2/28. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import "ZSDRefreshBaseView.h" 10 | 11 | #define kArrowSize CGSizeMake(22.0f,22.0f) 12 | 13 | @interface ZSDRefreshBaseView () 14 | 15 | @end 16 | 17 | @implementation ZSDRefreshBaseView 18 | 19 | -(instancetype)initWithFrame:(CGRect)frame 20 | { 21 | self = [super initWithFrame:frame]; 22 | if(self) 23 | { 24 | frame.size.width = [UIScreen mainScreen].bounds.size.width; 25 | frame.size.height = kRefreshHeaderHeight; 26 | self.frame = frame; 27 | 28 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth; 29 | 30 | [self setup]; 31 | } 32 | 33 | return self; 34 | } 35 | 36 | -(void)setup 37 | { 38 | if(!_backgroundImageView) 39 | { 40 | _backgroundImageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, self.bounds.size.width, kRefreshHeaderHeight)]; 41 | _backgroundImageView.image = [UIImage imageNamed:@"pic_head_refresh_text"]; 42 | [self addSubview:_backgroundImageView]; 43 | } 44 | 45 | if(!_arrowCircleView) 46 | { 47 | _arrowCircleView = [[ZSDRefreshCircleView alloc]initWithFrame:CGRectMake(CGRectGetMidX(self.frame) - 80.0f, 50.0f, kArrowSize.width, kArrowSize.height)]; 48 | _arrowCircleView.image = [UIImage imageNamed:@"ico_bottom_arrow"]; 49 | [self addSubview:_arrowCircleView]; 50 | } 51 | 52 | if(!_textLabel) 53 | { 54 | _textLabel = [[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(_arrowCircleView.frame) + 13.0f, CGRectGetMinY(_arrowCircleView.frame), 150.0f, kArrowSize.height)]; 55 | _textLabel.backgroundColor = [UIColor clearColor]; 56 | _textLabel.font = [UIFont systemFontOfSize:17.0f]; 57 | _textLabel.textColor = [UIColor grayColor]; 58 | [self addSubview:_textLabel]; 59 | } 60 | 61 | self.state = ZSDRefreshStateNormal; 62 | } 63 | 64 | -(void)willMoveToSuperview:(UIView *)newSuperview 65 | { 66 | [super willMoveToSuperview:newSuperview]; 67 | 68 | // 旧的父控件 69 | [self.superview removeObserver:self forKeyPath:kOffsetObserveKey context:nil]; 70 | 71 | if (newSuperview) { // 新的父控件 72 | [newSuperview addObserver:self forKeyPath:kOffsetObserveKey options:NSKeyValueObservingOptionNew context:nil]; 73 | 74 | // 记录UIScrollView 75 | _scrollView = (UIScrollView *)newSuperview; 76 | _scrollViewOriginalInset = _scrollView.contentInset; 77 | } 78 | } 79 | 80 | - (void)settingLabelText 81 | { 82 | // 设置文字 83 | switch (self.state) 84 | { 85 | case ZSDRefreshStateNormal: 86 | case ZSDRefreshStatePulling: 87 | self.textLabel.text = @"下拉刷新..."; 88 | break; 89 | case ZSDRefreshStateWillRefreshing: 90 | self.textLabel.text = @"释放即可刷新..."; 91 | break; 92 | case ZSDRefreshStateRefreshing: 93 | self.textLabel.text = @"正在努力加载..."; 94 | break; 95 | default: 96 | break; 97 | } 98 | } 99 | 100 | -(void)setState:(ZSDRefreshState)state 101 | { 102 | if(_scrollView.isDragging && state == ZSDRefreshStatePulling) 103 | { 104 | CGFloat offset = _scrollView.contentOffset.y - _scrollViewOriginalInset.top; 105 | 106 | if(_arrowCircleView.isHidden == NO) 107 | { 108 | _arrowCircleView.progress = MIN(-offset / kRefreshHeaderHeight, 1); 109 | } 110 | } 111 | 112 | if(_state != state) 113 | { 114 | //存储当前的contentInset 115 | if (_state != ZSDRefreshStateRefreshing) { 116 | _scrollViewOriginalInset = self.scrollView.contentInset; 117 | } 118 | 119 | switch (state) 120 | { 121 | case ZSDRefreshStateNormal: 122 | { 123 | if(_arrowCircleView.isHidden == NO) 124 | { 125 | _arrowCircleView.progress = 0; 126 | 127 | [_arrowCircleView stopAnimation]; 128 | } 129 | } 130 | break; 131 | case ZSDRefreshStatePulling: 132 | { 133 | 134 | } 135 | break; 136 | case ZSDRefreshStateRefreshing: 137 | { 138 | if(_arrowCircleView.isHidden == NO) 139 | { 140 | _arrowCircleView.progress = 1; 141 | 142 | [_arrowCircleView startAnimation]; 143 | } 144 | 145 | if(_beginRefreshCallback) 146 | { 147 | _beginRefreshCallback(); 148 | } 149 | } 150 | break; 151 | case ZSDRefreshStateWillRefreshing: 152 | break; 153 | default: 154 | break; 155 | } 156 | 157 | _state = state; 158 | 159 | [self settingLabelText]; 160 | } 161 | } 162 | 163 | #pragma mark 开始刷新 164 | - (void)beginRefresh 165 | { 166 | if (self.state == ZSDRefreshStateRefreshing) 167 | { 168 | if (_beginRefreshCallback) { 169 | _beginRefreshCallback(); 170 | } 171 | } 172 | else 173 | { 174 | self.state = ZSDRefreshStateRefreshing; 175 | } 176 | } 177 | 178 | #pragma mark 结束刷新 179 | - (void)endRefresh 180 | { 181 | double delayInSeconds = 0.3f; 182 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); 183 | dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 184 | self.state = ZSDRefreshStateNormal; 185 | }); 186 | } 187 | 188 | /* 189 | // Only override drawRect: if you perform custom drawing. 190 | // An empty implementation adversely affects performance during animation. 191 | - (void)drawRect:(CGRect)rect { 192 | // Drawing code 193 | } 194 | */ 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshCircleView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshCircleView.h 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/2/28. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZSDRefreshCircleView : UIView 12 | 13 | @property (nonatomic,copy) UIImage *image; 14 | @property (nonatomic,assign) CGFloat progress; //圆形进度,值为0~1 15 | 16 | -(void)startAnimation; 17 | -(void)stopAnimation; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshCircleView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshCircleView.m 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/2/28. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | //---------------下拉刷新转动的圆圈-------------- 8 | 9 | #import "ZSDRefreshCircleView.h" 10 | 11 | @interface ZSDRefreshCircleView () 12 | { 13 | UIImageView *imageView; 14 | 15 | CAShapeLayer *circleLayer; 16 | CAShapeLayer *arrowLayer; 17 | } 18 | 19 | @end 20 | 21 | @implementation ZSDRefreshCircleView 22 | 23 | - (id)initWithFrame:(CGRect)frame 24 | { 25 | self = [super initWithFrame:frame]; 26 | if (self) { 27 | // Initialization code 28 | // self.backgroundColor = [UIColor clearColor]; 29 | 30 | circleLayer = [CAShapeLayer layer]; 31 | circleLayer.frame = self.bounds; 32 | circleLayer.lineWidth = 1.5f; 33 | circleLayer.strokeColor = UIColorFromRGB(0x999999).CGColor; 34 | circleLayer.fillColor = nil; 35 | circleLayer.lineCap = kCALineCapRound; 36 | [self.layer addSublayer:circleLayer]; 37 | 38 | arrowLayer = [CAShapeLayer layer]; 39 | arrowLayer.frame = CGRectMake(4.0f, 3.0f, frame.size.width - 2 * 4.0f, frame.size.height - 2 * 3.0f); 40 | arrowLayer.fillColor = nil; 41 | [self.layer addSublayer:arrowLayer]; 42 | 43 | // [self setup]; 44 | } 45 | return self; 46 | } 47 | 48 | -(void)setup 49 | { 50 | if(!imageView) 51 | { 52 | imageView = [[UIImageView alloc]initWithFrame:self.bounds]; 53 | [self addSubview:imageView]; 54 | } 55 | } 56 | 57 | -(void)setImage:(UIImage *)image 58 | { 59 | if(_image != image) 60 | { 61 | _image = image; 62 | 63 | // imageView.image = _image; 64 | arrowLayer.contents = (id)_image.CGImage; 65 | } 66 | } 67 | 68 | -(void)setProgress:(CGFloat)progress 69 | { 70 | if(_progress != progress) 71 | { 72 | _progress = progress; 73 | 74 | [self drawPath]; 75 | } 76 | } 77 | 78 | -(void)drawPath 79 | { 80 | UIBezierPath *path = [UIBezierPath bezierPath]; 81 | 82 | CGFloat startAngle = -M_PI_2; 83 | CGFloat step = M_PI * 1.8f * self.progress; 84 | 85 | CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidX(self.bounds)); 86 | [path addArcWithCenter:center radius:self.bounds.size.width / 2.0f startAngle:startAngle endAngle:startAngle + step clockwise:YES]; 87 | 88 | circleLayer.path = [path CGPath]; 89 | } 90 | 91 | - (id)initWithCoder:(NSCoder *)aDecoder 92 | { 93 | self = [super initWithCoder:aDecoder]; 94 | if (self) { 95 | self.backgroundColor = [UIColor clearColor]; 96 | 97 | [self setup]; 98 | } 99 | return self; 100 | } 101 | 102 | /** 103 | * 开始动画 104 | */ 105 | -(void)startAnimation 106 | { 107 | [circleLayer removeAnimationForKey:@"RotationAnimation"]; 108 | 109 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 110 | animation.fromValue = @(0); 111 | animation.toValue = @(M_PI * 2); 112 | animation.repeatCount = MAXFLOAT; 113 | animation.duration = 0.5f; 114 | animation.fillMode = kCAFillModeForwards; 115 | 116 | [circleLayer addAnimation:animation forKey:@"RotationAnimation"]; 117 | } 118 | 119 | /** 120 | * 停止动画 121 | */ 122 | -(void)stopAnimation 123 | { 124 | [circleLayer removeAnimationForKey:@"RotationAnimation"]; 125 | } 126 | 127 | // Only override drawRect: if you perform custom drawing. 128 | // An empty implementation adversely affects performance during animation. 129 | //- (void)drawRect:(CGRect)rect { 130 | // // Drawing code 131 | // if(_progress == 0) 132 | // { 133 | // return; 134 | // } 135 | // 136 | // CGContextRef context = UIGraphicsGetCurrentContext(); 137 | // 138 | // CGContextSetLineWidth(context, 3.0f); 139 | // CGContextSetStrokeColorWithColor(context, [UIColor grayColor].CGColor); 140 | // CGFloat startAngle = -M_PI_2; 141 | // CGFloat step = M_PI * 1.9f * self.progress; 142 | // CGContextAddArc(context, rect.size.width / 2.0f, rect.size.height / 2.0f, rect.size.width / 2.0f - 1, startAngle, startAngle + step, 0); 143 | // CGContextStrokePath(context); 144 | //} 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshFootView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshFootView.h 3 | // demo 4 | // 5 | // Created by shaw on 15/4/11. 6 | // Copyright (c) 2015年 shaw. All rights reserved. 7 | // 8 | 9 | #import "ZSDRefreshBaseView.h" 10 | 11 | @interface ZSDRefreshFootView : ZSDRefreshBaseView 12 | 13 | +(instancetype)footer; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshFootView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshFootView.m 3 | // demo 4 | // 5 | // Created by shaw on 15/4/11. 6 | // Copyright (c) 2015年 shaw. All rights reserved. 7 | // 8 | 9 | #import "ZSDRefreshFootView.h" 10 | 11 | @interface ZSDRefreshFootView () 12 | 13 | @end 14 | 15 | @implementation ZSDRefreshFootView 16 | 17 | +(instancetype)footer 18 | { 19 | return [[ZSDRefreshFootView alloc]init]; 20 | } 21 | 22 | -(void)willMoveToSuperview:(UIView *)newSuperview 23 | { 24 | [super willMoveToSuperview:newSuperview]; 25 | 26 | // 旧的父控件 27 | [self.superview removeObserver:self forKeyPath:kContentSizeObserveKey context:nil]; 28 | 29 | if (newSuperview) { // 新的父控件 30 | // 监听 31 | [newSuperview addObserver:self forKeyPath:kContentSizeObserveKey options:NSKeyValueObservingOptionNew context:nil]; 32 | 33 | // 重新调整frame 34 | [self adjustFrameWithContentSize]; 35 | } 36 | 37 | // 设置位置和尺寸 38 | CGRect frect = self.frame; 39 | frect.size.height = kRefreshFooterHeight; 40 | self.frame = frect; 41 | } 42 | 43 | -(void)adjustFrameWithContentSize 44 | { 45 | // 内容的高度 46 | CGFloat contentHeight = self.scrollView.contentSize.height; 47 | // 表格的高度 48 | CGFloat scrollHeight = self.scrollView.frame.size.height - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom; 49 | 50 | CGRect frect = self.frame; 51 | frect.origin.y = MAX(contentHeight, scrollHeight); 52 | self.frame = frect; 53 | } 54 | 55 | -(void)layoutSubviews 56 | { 57 | [super layoutSubviews]; 58 | 59 | [self.arrowCircleView setHidden:YES]; 60 | [self.backgroundImageView setHidden:YES]; 61 | 62 | self.textLabel.backgroundColor = UIColorFromRGB(0xecedf1); 63 | self.textLabel.textAlignment = NSTextAlignmentCenter; 64 | self.textLabel.frame = self.bounds; 65 | } 66 | 67 | -(void)settingLabelText 68 | { 69 | switch (self.state) 70 | { 71 | case ZSDRefreshStateNormal: 72 | case ZSDRefreshStatePulling: 73 | self.textLabel.text = @"上拉加载更多..."; 74 | break; 75 | case ZSDRefreshStateWillRefreshing: 76 | self.textLabel.text = @"上拉加载更多..."; 77 | break; 78 | case ZSDRefreshStateRefreshing: 79 | self.textLabel.text = @"正在努力加载..."; 80 | break; 81 | default: 82 | break; 83 | } 84 | } 85 | 86 | /** 87 | * 调整状态 88 | */ 89 | - (void)adjustStateWithContentOffset 90 | { 91 | // 头部控件刚好出现的offsetY 92 | CGFloat happenOffsetY = 0; 93 | // 内容的高度 94 | CGFloat contentHeight = self.scrollView.contentSize.height; 95 | // 表格的高度 96 | CGFloat scrollHeight = self.scrollView.frame.size.height - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom; 97 | CGFloat distance = contentHeight - scrollHeight; 98 | if(distance > 0) 99 | { 100 | happenOffsetY = distance - self.scrollViewOriginalInset.top; 101 | } 102 | else 103 | { 104 | happenOffsetY = -self.scrollViewOriginalInset.top; 105 | } 106 | 107 | // 当前的contentOffset 108 | CGFloat currentOffsetY = self.scrollView.contentOffset.y; 109 | 110 | // 如果是向下滚动到看不见头部控件,直接返回 111 | if (currentOffsetY <= happenOffsetY) 112 | { 113 | return; 114 | } 115 | 116 | CGFloat normal2pullingOffsetY = happenOffsetY + self.bounds.size.height; 117 | if (self.scrollView.isDragging) 118 | { 119 | // 普通 和 即将刷新 的临界点 120 | if (self.state == ZSDRefreshStateNormal && currentOffsetY > happenOffsetY) 121 | { 122 | //转为下拉状态 123 | self.state = ZSDRefreshStatePulling; 124 | } 125 | if(currentOffsetY <= normal2pullingOffsetY) 126 | { 127 | self.state = ZSDRefreshStatePulling; 128 | } 129 | if(self.state == ZSDRefreshStatePulling && currentOffsetY >= normal2pullingOffsetY) 130 | { 131 | // 转为即将刷新状态 132 | self.state = ZSDRefreshStateWillRefreshing; 133 | } 134 | } 135 | else 136 | { 137 | if (self.state == ZSDRefreshStatePulling) 138 | { 139 | if (currentOffsetY < normal2pullingOffsetY) { 140 | // 转为普通状态 141 | self.state = ZSDRefreshStateNormal; 142 | } 143 | } 144 | else if(self.state == ZSDRefreshStateWillRefreshing) 145 | { 146 | // 即将刷新 && 手松开 147 | self.state = ZSDRefreshStateRefreshing; 148 | } 149 | } 150 | } 151 | 152 | -(void)setState:(ZSDRefreshState)state 153 | { 154 | if(state == ZSDRefreshStatePulling && self.state == ZSDRefreshStatePulling) 155 | { 156 | [super setState:state]; 157 | } 158 | if(self.state != state) 159 | { 160 | ZSDRefreshState oldState = self.state; 161 | 162 | [super setState:state]; 163 | 164 | switch (state) { 165 | case ZSDRefreshStateNormal: 166 | { 167 | if(oldState == ZSDRefreshStateRefreshing) 168 | { 169 | [UIView animateWithDuration:0.3f animations:^{ 170 | UIEdgeInsets insets = self.scrollView.contentInset; 171 | insets.bottom = self.scrollViewOriginalInset.bottom; 172 | self.scrollView.contentInset = insets; 173 | }]; 174 | } 175 | } 176 | break; 177 | case ZSDRefreshStatePulling: 178 | break; 179 | case ZSDRefreshStateRefreshing: 180 | { 181 | [UIView animateWithDuration:0.3f animations:^{ 182 | UIEdgeInsets inset = self.scrollView.contentInset; 183 | inset.bottom = self.scrollViewOriginalInset.bottom + self.bounds.size.height; 184 | 185 | // 内容的高度 186 | CGFloat contentHeight = self.scrollView.contentSize.height; 187 | // 表格的高度 188 | CGFloat scrollHeight = self.scrollView.frame.size.height - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom; 189 | CGFloat distance = contentHeight - scrollHeight; 190 | if(distance < 0) 191 | { 192 | inset.bottom -= distance; 193 | } 194 | self.scrollView.contentInset = inset; 195 | }]; 196 | } 197 | break; 198 | default: 199 | break; 200 | } 201 | } 202 | } 203 | 204 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 205 | { 206 | if([keyPath isEqualToString:kContentSizeObserveKey]) 207 | { 208 | if(self.state != ZSDRefreshStateRefreshing) 209 | { 210 | [self adjustFrameWithContentSize]; 211 | } 212 | } 213 | else if ([keyPath isEqualToString:kOffsetObserveKey]) 214 | { 215 | if(self.state != ZSDRefreshStateRefreshing) 216 | { 217 | [self adjustStateWithContentOffset]; 218 | } 219 | } 220 | } 221 | 222 | /* 223 | // Only override drawRect: if you perform custom drawing. 224 | // An empty implementation adversely affects performance during animation. 225 | - (void)drawRect:(CGRect)rect { 226 | // Drawing code 227 | } 228 | */ 229 | 230 | @end 231 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshHeadView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshHeadView.h 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/2/28. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ZSDRefreshBaseView.h" 11 | 12 | @interface ZSDRefreshHeadView : ZSDRefreshBaseView 13 | 14 | +(instancetype)header; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /refreshDemo/refreshView/ZSDRefreshHeadView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZSDRefreshHeadView.m 3 | // demo 4 | // 5 | // Created by zhaoxiao on 15/2/28. 6 | // Copyright (c) 2015年 zhaoxiao. All rights reserved. 7 | // 8 | 9 | #import "ZSDRefreshHeadView.h" 10 | 11 | @implementation ZSDRefreshHeadView 12 | 13 | +(instancetype)header 14 | { 15 | return [[ZSDRefreshHeadView alloc]init]; 16 | } 17 | 18 | -(void)willMoveToSuperview:(UIView *)newSuperview 19 | { 20 | [super willMoveToSuperview:newSuperview]; 21 | 22 | CGRect frect = self.frame; 23 | frect.origin.y = -frect.size.height; 24 | self.frame = frect; 25 | } 26 | 27 | /** 28 | * 调整状态 29 | */ 30 | - (void)adjustStateWithContentOffset 31 | { 32 | // 当前的contentOffset 33 | CGFloat currentOffsetY = self.scrollView.contentOffset.y; 34 | // 头部控件刚好出现的offsetY 35 | CGFloat happenOffsetY = -self.scrollViewOriginalInset.top; 36 | 37 | // 如果是向上滚动到看不见头部控件,直接返回 38 | if (currentOffsetY >= happenOffsetY) 39 | { 40 | return; 41 | } 42 | 43 | CGFloat normal2pullingOffsetY = happenOffsetY - self.bounds.size.height; 44 | if (self.scrollView.isDragging) 45 | { 46 | // 普通 和 即将刷新 的临界点 47 | if (self.state == ZSDRefreshStateNormal && currentOffsetY < happenOffsetY) 48 | { 49 | //转为下拉状态 50 | self.state = ZSDRefreshStatePulling; 51 | } 52 | if(currentOffsetY > normal2pullingOffsetY) 53 | { 54 | self.state = ZSDRefreshStatePulling; 55 | } 56 | if(self.state == ZSDRefreshStatePulling && currentOffsetY < normal2pullingOffsetY) 57 | { 58 | // 转为即将刷新状态 59 | self.state = ZSDRefreshStateWillRefreshing; 60 | } 61 | } 62 | else 63 | { 64 | if (self.state == ZSDRefreshStatePulling) 65 | { 66 | if (currentOffsetY >= normal2pullingOffsetY) { 67 | // 转为普通状态 68 | self.state = ZSDRefreshStateNormal; 69 | } 70 | } 71 | else if(self.state == ZSDRefreshStateWillRefreshing) 72 | { 73 | // 即将刷新 && 手松开 74 | self.state = ZSDRefreshStateRefreshing; 75 | } 76 | } 77 | } 78 | 79 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 80 | { 81 | if([keyPath isEqualToString:kOffsetObserveKey]) 82 | { 83 | if(self.state != ZSDRefreshStateRefreshing) 84 | { 85 | [self adjustStateWithContentOffset]; 86 | } 87 | } 88 | } 89 | 90 | -(void)setState:(ZSDRefreshState)state 91 | { 92 | if(state == ZSDRefreshStatePulling && self.state == ZSDRefreshStatePulling) 93 | { 94 | [super setState:state]; 95 | } 96 | if(self.state != state) 97 | { 98 | ZSDRefreshState oldState = self.state; 99 | 100 | [super setState:state]; 101 | 102 | switch (state) { 103 | case ZSDRefreshStateNormal: 104 | { 105 | if(oldState == ZSDRefreshStateRefreshing) 106 | { 107 | [UIView animateWithDuration:0.3f animations:^{ 108 | UIEdgeInsets inset = self.scrollView.contentInset; 109 | inset.top -= self.bounds.size.height; 110 | self.scrollView.contentInset = inset; 111 | }]; 112 | } 113 | } 114 | break; 115 | case ZSDRefreshStatePulling: 116 | break; 117 | case ZSDRefreshStateRefreshing: 118 | { 119 | [UIView animateWithDuration:0.3f animations:^{ 120 | UIEdgeInsets inset = self.scrollView.contentInset; 121 | inset.top = self.scrollViewOriginalInset.top + self.bounds.size.height; 122 | self.scrollView.contentInset = inset; 123 | 124 | CGPoint offset = self.scrollView.contentOffset; 125 | offset.y = -inset.top; 126 | self.scrollView.contentOffset = offset; 127 | }]; 128 | } 129 | break; 130 | default: 131 | break; 132 | } 133 | } 134 | } 135 | 136 | /* 137 | // Only override drawRect: if you perform custom drawing. 138 | // An empty implementation adversely affects performance during animation. 139 | - (void)drawRect:(CGRect)rect { 140 | // Drawing code 141 | } 142 | */ 143 | 144 | @end 145 | --------------------------------------------------------------------------------