├── README.md ├── YSimilarZHPullDownDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── yuewen.xcuserdatad │ └── xcschemes │ ├── YSimilarZHPullDownDemo.xcscheme │ └── xcschememanagement.plist └── YSimilarZHPullDownDemo ├── AppDelegate.swift ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Image ├── ZhiHu.gif └── testImage.jpg ├── Info.plist ├── ViewController.swift └── YSimilarZHPullDownView ├── SimilarZHPullDownView.swift └── YSimilarZHPullDownMainView.swift /README.md: -------------------------------------------------------------------------------- 1 | # RITLSimilarZHPullDownDemo 2 | 类似知乎上下滑动切换视图实现 3 | 4 | # 2018-03-24 5 | 现在的知乎已经不是这样的样式了,并且当时只是为了研究一下思路,并没有做任何的性能以及相关逻辑的处理,仅供参考。 6 | 7 | 效果图: 8 | 9 | ![效果图](https://github.com/YRunIntoLove/YSimilarZHPullDownDemo/raw/master/YSimilarZHPullDownDemo/Image/ZhiHu.gif) 10 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | DB1627B61C963AD900A3DFB4 /* YSimilarZHPullDownMainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB1627B51C963AD900A3DFB4 /* YSimilarZHPullDownMainView.swift */; }; 11 | DB1F59CD1C95523600C66C01 /* testImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = DB1F59CC1C95523600C66C01 /* testImage.jpg */; }; 12 | DB2CAE891C96AB730048BF31 /* ZhiHu.gif in Resources */ = {isa = PBXBuildFile; fileRef = DB2CAE881C96AB730048BF31 /* ZhiHu.gif */; }; 13 | DB431E421C8E79C1000D5C90 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB431E411C8E79C1000D5C90 /* AppDelegate.swift */; }; 14 | DB431E441C8E79C1000D5C90 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB431E431C8E79C1000D5C90 /* ViewController.swift */; }; 15 | DB431E471C8E79C1000D5C90 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB431E451C8E79C1000D5C90 /* Main.storyboard */; }; 16 | DB431E491C8E79C1000D5C90 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB431E481C8E79C1000D5C90 /* Assets.xcassets */; }; 17 | DB431E4C1C8E79C1000D5C90 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DB431E4A1C8E79C1000D5C90 /* LaunchScreen.storyboard */; }; 18 | DB431E711C8E79F9000D5C90 /* SimilarZHPullDownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB431E701C8E79F9000D5C90 /* SimilarZHPullDownView.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | DB431E531C8E79C1000D5C90 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = DB431E361C8E79C1000D5C90 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = DB431E3D1C8E79C1000D5C90; 27 | remoteInfo = YSimilarZHPullDownDemo; 28 | }; 29 | DB431E5E1C8E79C1000D5C90 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = DB431E361C8E79C1000D5C90 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = DB431E3D1C8E79C1000D5C90; 34 | remoteInfo = YSimilarZHPullDownDemo; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | DB1627B51C963AD900A3DFB4 /* YSimilarZHPullDownMainView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YSimilarZHPullDownMainView.swift; sourceTree = ""; }; 40 | DB1F59CC1C95523600C66C01 /* testImage.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = testImage.jpg; sourceTree = ""; }; 41 | DB2CAE881C96AB730048BF31 /* ZhiHu.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ZhiHu.gif; sourceTree = ""; }; 42 | DB431E3E1C8E79C1000D5C90 /* YSimilarZHPullDownDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YSimilarZHPullDownDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | DB431E411C8E79C1000D5C90 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 44 | DB431E431C8E79C1000D5C90 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 45 | DB431E461C8E79C1000D5C90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 46 | DB431E481C8E79C1000D5C90 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 47 | DB431E4B1C8E79C1000D5C90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 48 | DB431E4D1C8E79C1000D5C90 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 49 | DB431E521C8E79C1000D5C90 /* YSimilarZHPullDownDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YSimilarZHPullDownDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | DB431E5D1C8E79C1000D5C90 /* YSimilarZHPullDownDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YSimilarZHPullDownDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | DB431E701C8E79F9000D5C90 /* SimilarZHPullDownView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimilarZHPullDownView.swift; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | DB431E3B1C8E79C1000D5C90 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | DB431E4F1C8E79C1000D5C90 /* Frameworks */ = { 63 | isa = PBXFrameworksBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | ); 67 | runOnlyForDeploymentPostprocessing = 0; 68 | }; 69 | DB431E5A1C8E79C1000D5C90 /* Frameworks */ = { 70 | isa = PBXFrameworksBuildPhase; 71 | buildActionMask = 2147483647; 72 | files = ( 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | DB1F59CB1C95523600C66C01 /* Image */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | DB2CAE881C96AB730048BF31 /* ZhiHu.gif */, 83 | DB1F59CC1C95523600C66C01 /* testImage.jpg */, 84 | ); 85 | path = Image; 86 | sourceTree = ""; 87 | }; 88 | DB431E351C8E79C1000D5C90 = { 89 | isa = PBXGroup; 90 | children = ( 91 | DB431E401C8E79C1000D5C90 /* YSimilarZHPullDownDemo */, 92 | DB431E3F1C8E79C1000D5C90 /* Products */, 93 | ); 94 | sourceTree = ""; 95 | }; 96 | DB431E3F1C8E79C1000D5C90 /* Products */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | DB431E3E1C8E79C1000D5C90 /* YSimilarZHPullDownDemo.app */, 100 | DB431E521C8E79C1000D5C90 /* YSimilarZHPullDownDemoTests.xctest */, 101 | DB431E5D1C8E79C1000D5C90 /* YSimilarZHPullDownDemoUITests.xctest */, 102 | ); 103 | name = Products; 104 | sourceTree = ""; 105 | }; 106 | DB431E401C8E79C1000D5C90 /* YSimilarZHPullDownDemo */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | DB1F59CB1C95523600C66C01 /* Image */, 110 | DB431E6F1C8E79E5000D5C90 /* YSimilarZHPullDownView */, 111 | DB431E411C8E79C1000D5C90 /* AppDelegate.swift */, 112 | DB431E431C8E79C1000D5C90 /* ViewController.swift */, 113 | DB431E451C8E79C1000D5C90 /* Main.storyboard */, 114 | DB431E481C8E79C1000D5C90 /* Assets.xcassets */, 115 | DB431E4A1C8E79C1000D5C90 /* LaunchScreen.storyboard */, 116 | DB431E4D1C8E79C1000D5C90 /* Info.plist */, 117 | ); 118 | path = YSimilarZHPullDownDemo; 119 | sourceTree = ""; 120 | }; 121 | DB431E6F1C8E79E5000D5C90 /* YSimilarZHPullDownView */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | DB431E701C8E79F9000D5C90 /* SimilarZHPullDownView.swift */, 125 | DB1627B51C963AD900A3DFB4 /* YSimilarZHPullDownMainView.swift */, 126 | ); 127 | path = YSimilarZHPullDownView; 128 | sourceTree = ""; 129 | }; 130 | /* End PBXGroup section */ 131 | 132 | /* Begin PBXNativeTarget section */ 133 | DB431E3D1C8E79C1000D5C90 /* YSimilarZHPullDownDemo */ = { 134 | isa = PBXNativeTarget; 135 | buildConfigurationList = DB431E661C8E79C1000D5C90 /* Build configuration list for PBXNativeTarget "YSimilarZHPullDownDemo" */; 136 | buildPhases = ( 137 | DB431E3A1C8E79C1000D5C90 /* Sources */, 138 | DB431E3B1C8E79C1000D5C90 /* Frameworks */, 139 | DB431E3C1C8E79C1000D5C90 /* Resources */, 140 | ); 141 | buildRules = ( 142 | ); 143 | dependencies = ( 144 | ); 145 | name = YSimilarZHPullDownDemo; 146 | productName = YSimilarZHPullDownDemo; 147 | productReference = DB431E3E1C8E79C1000D5C90 /* YSimilarZHPullDownDemo.app */; 148 | productType = "com.apple.product-type.application"; 149 | }; 150 | DB431E511C8E79C1000D5C90 /* YSimilarZHPullDownDemoTests */ = { 151 | isa = PBXNativeTarget; 152 | buildConfigurationList = DB431E691C8E79C1000D5C90 /* Build configuration list for PBXNativeTarget "YSimilarZHPullDownDemoTests" */; 153 | buildPhases = ( 154 | DB431E4E1C8E79C1000D5C90 /* Sources */, 155 | DB431E4F1C8E79C1000D5C90 /* Frameworks */, 156 | DB431E501C8E79C1000D5C90 /* Resources */, 157 | ); 158 | buildRules = ( 159 | ); 160 | dependencies = ( 161 | DB431E541C8E79C1000D5C90 /* PBXTargetDependency */, 162 | ); 163 | name = YSimilarZHPullDownDemoTests; 164 | productName = YSimilarZHPullDownDemoTests; 165 | productReference = DB431E521C8E79C1000D5C90 /* YSimilarZHPullDownDemoTests.xctest */; 166 | productType = "com.apple.product-type.bundle.unit-test"; 167 | }; 168 | DB431E5C1C8E79C1000D5C90 /* YSimilarZHPullDownDemoUITests */ = { 169 | isa = PBXNativeTarget; 170 | buildConfigurationList = DB431E6C1C8E79C1000D5C90 /* Build configuration list for PBXNativeTarget "YSimilarZHPullDownDemoUITests" */; 171 | buildPhases = ( 172 | DB431E591C8E79C1000D5C90 /* Sources */, 173 | DB431E5A1C8E79C1000D5C90 /* Frameworks */, 174 | DB431E5B1C8E79C1000D5C90 /* Resources */, 175 | ); 176 | buildRules = ( 177 | ); 178 | dependencies = ( 179 | DB431E5F1C8E79C1000D5C90 /* PBXTargetDependency */, 180 | ); 181 | name = YSimilarZHPullDownDemoUITests; 182 | productName = YSimilarZHPullDownDemoUITests; 183 | productReference = DB431E5D1C8E79C1000D5C90 /* YSimilarZHPullDownDemoUITests.xctest */; 184 | productType = "com.apple.product-type.bundle.ui-testing"; 185 | }; 186 | /* End PBXNativeTarget section */ 187 | 188 | /* Begin PBXProject section */ 189 | DB431E361C8E79C1000D5C90 /* Project object */ = { 190 | isa = PBXProject; 191 | attributes = { 192 | CLASSPREFIX = Y; 193 | LastSwiftUpdateCheck = 0720; 194 | LastUpgradeCheck = 0720; 195 | ORGANIZATIONNAME = YueWen; 196 | TargetAttributes = { 197 | DB431E3D1C8E79C1000D5C90 = { 198 | CreatedOnToolsVersion = 7.2.1; 199 | DevelopmentTeam = 8S4NWFZC5J; 200 | LastSwiftMigration = 0820; 201 | }; 202 | DB431E511C8E79C1000D5C90 = { 203 | CreatedOnToolsVersion = 7.2.1; 204 | LastSwiftMigration = 0820; 205 | TestTargetID = DB431E3D1C8E79C1000D5C90; 206 | }; 207 | DB431E5C1C8E79C1000D5C90 = { 208 | CreatedOnToolsVersion = 7.2.1; 209 | LastSwiftMigration = 0820; 210 | TestTargetID = DB431E3D1C8E79C1000D5C90; 211 | }; 212 | }; 213 | }; 214 | buildConfigurationList = DB431E391C8E79C1000D5C90 /* Build configuration list for PBXProject "YSimilarZHPullDownDemo" */; 215 | compatibilityVersion = "Xcode 3.2"; 216 | developmentRegion = English; 217 | hasScannedForEncodings = 0; 218 | knownRegions = ( 219 | en, 220 | Base, 221 | ); 222 | mainGroup = DB431E351C8E79C1000D5C90; 223 | productRefGroup = DB431E3F1C8E79C1000D5C90 /* Products */; 224 | projectDirPath = ""; 225 | projectRoot = ""; 226 | targets = ( 227 | DB431E3D1C8E79C1000D5C90 /* YSimilarZHPullDownDemo */, 228 | DB431E511C8E79C1000D5C90 /* YSimilarZHPullDownDemoTests */, 229 | DB431E5C1C8E79C1000D5C90 /* YSimilarZHPullDownDemoUITests */, 230 | ); 231 | }; 232 | /* End PBXProject section */ 233 | 234 | /* Begin PBXResourcesBuildPhase section */ 235 | DB431E3C1C8E79C1000D5C90 /* Resources */ = { 236 | isa = PBXResourcesBuildPhase; 237 | buildActionMask = 2147483647; 238 | files = ( 239 | DB431E4C1C8E79C1000D5C90 /* LaunchScreen.storyboard in Resources */, 240 | DB431E491C8E79C1000D5C90 /* Assets.xcassets in Resources */, 241 | DB431E471C8E79C1000D5C90 /* Main.storyboard in Resources */, 242 | DB1F59CD1C95523600C66C01 /* testImage.jpg in Resources */, 243 | DB2CAE891C96AB730048BF31 /* ZhiHu.gif in Resources */, 244 | ); 245 | runOnlyForDeploymentPostprocessing = 0; 246 | }; 247 | DB431E501C8E79C1000D5C90 /* Resources */ = { 248 | isa = PBXResourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | DB431E5B1C8E79C1000D5C90 /* Resources */ = { 255 | isa = PBXResourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | /* End PBXResourcesBuildPhase section */ 262 | 263 | /* Begin PBXSourcesBuildPhase section */ 264 | DB431E3A1C8E79C1000D5C90 /* Sources */ = { 265 | isa = PBXSourcesBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | DB1627B61C963AD900A3DFB4 /* YSimilarZHPullDownMainView.swift in Sources */, 269 | DB431E441C8E79C1000D5C90 /* ViewController.swift in Sources */, 270 | DB431E711C8E79F9000D5C90 /* SimilarZHPullDownView.swift in Sources */, 271 | DB431E421C8E79C1000D5C90 /* AppDelegate.swift in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | DB431E4E1C8E79C1000D5C90 /* Sources */ = { 276 | isa = PBXSourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | DB431E591C8E79C1000D5C90 /* Sources */ = { 283 | isa = PBXSourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | /* End PBXSourcesBuildPhase section */ 290 | 291 | /* Begin PBXTargetDependency section */ 292 | DB431E541C8E79C1000D5C90 /* PBXTargetDependency */ = { 293 | isa = PBXTargetDependency; 294 | target = DB431E3D1C8E79C1000D5C90 /* YSimilarZHPullDownDemo */; 295 | targetProxy = DB431E531C8E79C1000D5C90 /* PBXContainerItemProxy */; 296 | }; 297 | DB431E5F1C8E79C1000D5C90 /* PBXTargetDependency */ = { 298 | isa = PBXTargetDependency; 299 | target = DB431E3D1C8E79C1000D5C90 /* YSimilarZHPullDownDemo */; 300 | targetProxy = DB431E5E1C8E79C1000D5C90 /* PBXContainerItemProxy */; 301 | }; 302 | /* End PBXTargetDependency section */ 303 | 304 | /* Begin PBXVariantGroup section */ 305 | DB431E451C8E79C1000D5C90 /* Main.storyboard */ = { 306 | isa = PBXVariantGroup; 307 | children = ( 308 | DB431E461C8E79C1000D5C90 /* Base */, 309 | ); 310 | name = Main.storyboard; 311 | sourceTree = ""; 312 | }; 313 | DB431E4A1C8E79C1000D5C90 /* LaunchScreen.storyboard */ = { 314 | isa = PBXVariantGroup; 315 | children = ( 316 | DB431E4B1C8E79C1000D5C90 /* Base */, 317 | ); 318 | name = LaunchScreen.storyboard; 319 | sourceTree = ""; 320 | }; 321 | /* End PBXVariantGroup section */ 322 | 323 | /* Begin XCBuildConfiguration section */ 324 | DB431E641C8E79C1000D5C90 /* Debug */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ALWAYS_SEARCH_USER_PATHS = NO; 328 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 329 | CLANG_CXX_LIBRARY = "libc++"; 330 | CLANG_ENABLE_MODULES = YES; 331 | CLANG_ENABLE_OBJC_ARC = YES; 332 | CLANG_WARN_BOOL_CONVERSION = YES; 333 | CLANG_WARN_CONSTANT_CONVERSION = YES; 334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 335 | CLANG_WARN_EMPTY_BODY = YES; 336 | CLANG_WARN_ENUM_CONVERSION = YES; 337 | CLANG_WARN_INT_CONVERSION = YES; 338 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = dwarf; 344 | ENABLE_STRICT_OBJC_MSGSEND = YES; 345 | ENABLE_TESTABILITY = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_DYNAMIC_NO_PIC = NO; 348 | GCC_NO_COMMON_BLOCKS = YES; 349 | GCC_OPTIMIZATION_LEVEL = 0; 350 | GCC_PREPROCESSOR_DEFINITIONS = ( 351 | "DEBUG=1", 352 | "$(inherited)", 353 | ); 354 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 355 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 356 | GCC_WARN_UNDECLARED_SELECTOR = YES; 357 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 358 | GCC_WARN_UNUSED_FUNCTION = YES; 359 | GCC_WARN_UNUSED_VARIABLE = YES; 360 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 361 | MTL_ENABLE_DEBUG_INFO = YES; 362 | ONLY_ACTIVE_ARCH = YES; 363 | SDKROOT = iphoneos; 364 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 365 | }; 366 | name = Debug; 367 | }; 368 | DB431E651C8E79C1000D5C90 /* Release */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 373 | CLANG_CXX_LIBRARY = "libc++"; 374 | CLANG_ENABLE_MODULES = YES; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_CONSTANT_CONVERSION = YES; 378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 379 | CLANG_WARN_EMPTY_BODY = YES; 380 | CLANG_WARN_ENUM_CONVERSION = YES; 381 | CLANG_WARN_INT_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | VALIDATE_PRODUCT = YES; 402 | }; 403 | name = Release; 404 | }; 405 | DB431E671C8E79C1000D5C90 /* Debug */ = { 406 | isa = XCBuildConfiguration; 407 | buildSettings = { 408 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 409 | CODE_SIGN_IDENTITY = "iPhone Developer"; 410 | DEVELOPMENT_TEAM = 8S4NWFZC5J; 411 | INFOPLIST_FILE = YSimilarZHPullDownDemo/Info.plist; 412 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 413 | PRODUCT_BUNDLE_IDENTIFIER = com.yue.YSimilarZHPullDownDemo; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | SWIFT_VERSION = 3.0; 416 | }; 417 | name = Debug; 418 | }; 419 | DB431E681C8E79C1000D5C90 /* Release */ = { 420 | isa = XCBuildConfiguration; 421 | buildSettings = { 422 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 423 | CODE_SIGN_IDENTITY = "iPhone Developer"; 424 | DEVELOPMENT_TEAM = 8S4NWFZC5J; 425 | INFOPLIST_FILE = YSimilarZHPullDownDemo/Info.plist; 426 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 427 | PRODUCT_BUNDLE_IDENTIFIER = com.yue.YSimilarZHPullDownDemo; 428 | PRODUCT_NAME = "$(TARGET_NAME)"; 429 | SWIFT_VERSION = 3.0; 430 | }; 431 | name = Release; 432 | }; 433 | DB431E6A1C8E79C1000D5C90 /* Debug */ = { 434 | isa = XCBuildConfiguration; 435 | buildSettings = { 436 | BUNDLE_LOADER = "$(TEST_HOST)"; 437 | INFOPLIST_FILE = YSimilarZHPullDownDemoTests/Info.plist; 438 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 439 | PRODUCT_BUNDLE_IDENTIFIER = com.yue.YSimilarZHPullDownDemoTests; 440 | PRODUCT_NAME = "$(TARGET_NAME)"; 441 | SWIFT_VERSION = 3.0; 442 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/YSimilarZHPullDownDemo.app/YSimilarZHPullDownDemo"; 443 | }; 444 | name = Debug; 445 | }; 446 | DB431E6B1C8E79C1000D5C90 /* Release */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | BUNDLE_LOADER = "$(TEST_HOST)"; 450 | INFOPLIST_FILE = YSimilarZHPullDownDemoTests/Info.plist; 451 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 452 | PRODUCT_BUNDLE_IDENTIFIER = com.yue.YSimilarZHPullDownDemoTests; 453 | PRODUCT_NAME = "$(TARGET_NAME)"; 454 | SWIFT_VERSION = 3.0; 455 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/YSimilarZHPullDownDemo.app/YSimilarZHPullDownDemo"; 456 | }; 457 | name = Release; 458 | }; 459 | DB431E6D1C8E79C1000D5C90 /* Debug */ = { 460 | isa = XCBuildConfiguration; 461 | buildSettings = { 462 | INFOPLIST_FILE = YSimilarZHPullDownDemoUITests/Info.plist; 463 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 464 | PRODUCT_BUNDLE_IDENTIFIER = com.yue.YSimilarZHPullDownDemoUITests; 465 | PRODUCT_NAME = "$(TARGET_NAME)"; 466 | SWIFT_VERSION = 3.0; 467 | TEST_TARGET_NAME = YSimilarZHPullDownDemo; 468 | USES_XCTRUNNER = YES; 469 | }; 470 | name = Debug; 471 | }; 472 | DB431E6E1C8E79C1000D5C90 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | INFOPLIST_FILE = YSimilarZHPullDownDemoUITests/Info.plist; 476 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 477 | PRODUCT_BUNDLE_IDENTIFIER = com.yue.YSimilarZHPullDownDemoUITests; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | SWIFT_VERSION = 3.0; 480 | TEST_TARGET_NAME = YSimilarZHPullDownDemo; 481 | USES_XCTRUNNER = YES; 482 | }; 483 | name = Release; 484 | }; 485 | /* End XCBuildConfiguration section */ 486 | 487 | /* Begin XCConfigurationList section */ 488 | DB431E391C8E79C1000D5C90 /* Build configuration list for PBXProject "YSimilarZHPullDownDemo" */ = { 489 | isa = XCConfigurationList; 490 | buildConfigurations = ( 491 | DB431E641C8E79C1000D5C90 /* Debug */, 492 | DB431E651C8E79C1000D5C90 /* Release */, 493 | ); 494 | defaultConfigurationIsVisible = 0; 495 | defaultConfigurationName = Release; 496 | }; 497 | DB431E661C8E79C1000D5C90 /* Build configuration list for PBXNativeTarget "YSimilarZHPullDownDemo" */ = { 498 | isa = XCConfigurationList; 499 | buildConfigurations = ( 500 | DB431E671C8E79C1000D5C90 /* Debug */, 501 | DB431E681C8E79C1000D5C90 /* Release */, 502 | ); 503 | defaultConfigurationIsVisible = 0; 504 | defaultConfigurationName = Release; 505 | }; 506 | DB431E691C8E79C1000D5C90 /* Build configuration list for PBXNativeTarget "YSimilarZHPullDownDemoTests" */ = { 507 | isa = XCConfigurationList; 508 | buildConfigurations = ( 509 | DB431E6A1C8E79C1000D5C90 /* Debug */, 510 | DB431E6B1C8E79C1000D5C90 /* Release */, 511 | ); 512 | defaultConfigurationIsVisible = 0; 513 | defaultConfigurationName = Release; 514 | }; 515 | DB431E6C1C8E79C1000D5C90 /* Build configuration list for PBXNativeTarget "YSimilarZHPullDownDemoUITests" */ = { 516 | isa = XCConfigurationList; 517 | buildConfigurations = ( 518 | DB431E6D1C8E79C1000D5C90 /* Debug */, 519 | DB431E6E1C8E79C1000D5C90 /* Release */, 520 | ); 521 | defaultConfigurationIsVisible = 0; 522 | defaultConfigurationName = Release; 523 | }; 524 | /* End XCConfigurationList section */ 525 | }; 526 | rootObject = DB431E361C8E79C1000D5C90 /* Project object */; 527 | } 528 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo.xcodeproj/xcuserdata/yuewen.xcuserdatad/xcschemes/YSimilarZHPullDownDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo.xcodeproj/xcuserdata/yuewen.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | YSimilarZHPullDownDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | DB431E3D1C8E79C1000D5C90 16 | 17 | primary 18 | 19 | 20 | DB431E511C8E79C1000D5C90 21 | 22 | primary 23 | 24 | 25 | DB431E5C1C8E79C1000D5C90 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // YSimilarZHPullDownDemo 4 | // 5 | // Created by YueWen on 16/3/8. 6 | // Copyright © 2016年 YueWen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | 19 | //创建windows对象 20 | let window = UIWindow(frame: UIScreen.main.bounds) 21 | 22 | //获取storyBoard对象 23 | let storyBoard = UIStoryboard(name: "Main", bundle: Bundle.main) 24 | 25 | //获取主页控制器 26 | let viewController = storyBoard.instantiateViewController(withIdentifier: "ViewController") 27 | 28 | //定义导航控制器 29 | let navigationController = UINavigationController(rootViewController: viewController) 30 | 31 | //设置成rootViewController 32 | window.rootViewController = navigationController 33 | 34 | self.window = window 35 | 36 | self.window?.makeKeyAndVisible() 37 | 38 | // Override point for customization after application launch. 39 | return true 40 | } 41 | 42 | func applicationWillResignActive(_ application: UIApplication) { 43 | // 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. 44 | // 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. 45 | } 46 | 47 | func applicationDidEnterBackground(_ application: UIApplication) { 48 | // 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. 49 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 50 | } 51 | 52 | func applicationWillEnterForeground(_ application: UIApplication) { 53 | // 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. 54 | } 55 | 56 | func applicationDidBecomeActive(_ application: UIApplication) { 57 | // 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. 58 | } 59 | 60 | func applicationWillTerminate(_ application: UIApplication) { 61 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 62 | } 63 | 64 | 65 | func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask 66 | { 67 | return .portrait 68 | } 69 | 70 | 71 | } 72 | 73 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/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 | } -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/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 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/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 | 27 | 28 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/Image/ZhiHu.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RITL/RITLSimilarZHPullDownDemo/fbf97e45580941cf64de906fa64ed435f6a3029b/YSimilarZHPullDownDemo/Image/ZhiHu.gif -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/Image/testImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RITL/RITLSimilarZHPullDownDemo/fbf97e45580941cf64de906fa64ed435f6a3029b/YSimilarZHPullDownDemo/Image/testImage.jpg -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/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 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // YSimilarZHPullDownDemo 4 | // 5 | // Created by YueWen on 16/3/8. 6 | // Copyright © 2016年 YueWen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | 14 | var demoMainView : YSimilarZHPullDownMainView? 15 | 16 | override func viewDidLoad() 17 | { 18 | super.viewDidLoad() 19 | 20 | navigationItem.title = "Yue" 21 | 22 | //创建DemoMainView对象 23 | demoMainView = YSimilarZHPullDownMainView(frame:CGRect(x: 0,y: 0,width: view.bounds.width,height: view.bounds.height)) 24 | 25 | //赋值 26 | /*** 设置表头与表位文字需要设置数据源之前 ***/ 27 | demoMainView!.headerTitle = "啦啦啦,我已经是第一篇了" 28 | demoMainView!.footerTitle = "哈哈哈,我是最后一篇啦" 29 | demoMainView!.pullViews = createPullDownViews() 30 | 31 | //添加视图 32 | view.addSubview(demoMainView!) 33 | 34 | } 35 | 36 | 37 | 38 | 39 | override func didReceiveMemoryWarning() { 40 | super.didReceiveMemoryWarning() 41 | // Dispose of any resources that can be recreated. 42 | } 43 | 44 | 45 | 46 | 47 | /** 48 | * 创建测试PullDown视图 49 | */ 50 | func createPullDownViews() -> [SimilarZHPullDownView] 51 | { 52 | var views :[SimilarZHPullDownView] = [] 53 | 54 | for i in 0 ..< 4{ 55 | 56 | let similarPullDownView = SimilarZHPullDownView(frame: view.bounds, custom: createCustomView()) 57 | 58 | similarPullDownView.title = "测试\(i + 1)" 59 | 60 | views.append(similarPullDownView) 61 | } 62 | 63 | return views 64 | } 65 | 66 | 67 | //随机创建UIView的对象 68 | func createCustomView() -> UIView 69 | { 70 | //初始化视图 71 | let view = UIImageView() 72 | 73 | //获得随机数 74 | let count = arc4random() % 3 + 1 75 | // let count = 1 76 | 77 | view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height * CGFloat(count)) 78 | view.image = UIImage(named: "testImage.jpg") 79 | view.contentMode = .scaleToFill 80 | 81 | return view 82 | } 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/YSimilarZHPullDownView/SimilarZHPullDownView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimilarZHPullDownView.swift 3 | // YSimilarZHPullDownDemo 4 | // 5 | // Created by YueWen on 16/3/8. 6 | // Copyright © 2016年 YueWen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | /// 滑动响应的方式 13 | /// 14 | /// - pullTypeUp 上翻页 15 | /// - pullTypeDown 下翻页 16 | enum PullType 17 | { 18 | case up 19 | case down 20 | } 21 | 22 | /// 下拉的类型 23 | /// 24 | /// - middle: 默认中间 25 | /// - header: 第一页 26 | /// - footer: 最后一页 27 | enum SimilarZHPullDownType 28 | { 29 | case middle 30 | case header 31 | case footer 32 | } 33 | 34 | 35 | protocol SimilarZHPullDownViewDelegate : NSObjectProtocol 36 | { 37 | 38 | /// 需要翻页进行的回调 39 | /// 40 | /// - Parameters: 41 | /// - similarZHPullDownView: 进行回调的SimilarZHPullDownView 42 | /// - pullType: 翻页类型 43 | func similarZHPullDownView(_ similarZHPullDownView : SimilarZHPullDownView , pullType:PullType) 44 | 45 | } 46 | 47 | 48 | /// 类知乎的下拉换页 49 | class SimilarZHPullDownView: UIView 50 | { 51 | 52 | /// 响应的高度,就是滑动响应的最小幅度 53 | final let responseHeight = CGFloat(60) 54 | 55 | 56 | /// 懒加载底层的滚动视图 57 | lazy var bottomScrollView : UIScrollView = 58 | { 59 | //当前视图的宽度 60 | let width = self.bounds.width 61 | 62 | //初始化滚动视图 63 | var scrollView:UIScrollView = UIScrollView(frame:CGRect(x: 0, y: 0, width: width, height: self.bounds.height - 64 - 30)) 64 | 65 | 66 | scrollView.delegate = self; 67 | 68 | return scrollView 69 | }() 70 | 71 | 72 | 73 | /// 显示头部文字的label 74 | lazy var headerLabel : UILabel = { 75 | 76 | let label = UILabel(frame: CGRect(x: 0,y: -1 * self.responseHeight,width: self.bounds.width,height: 30)) 77 | 78 | label.textAlignment = .center 79 | label.font = UIFont.systemFont(ofSize: 12) 80 | 81 | return label 82 | }() 83 | 84 | 85 | 86 | /// 显示底部文字的label 87 | lazy var bottomLabel : UILabel = { 88 | 89 | let label = UILabel(frame: CGRect(x: 0,y: self.bounds.height,width: self.bounds.width,height: self.responseHeight)) 90 | 91 | label.textAlignment = .center 92 | label.font = UIFont.systemFont(ofSize: 12) 93 | 94 | return label 95 | }() 96 | 97 | 98 | /// 中间位置的自定义视图 99 | var customView:UIView? 100 | 101 | /// 代理 102 | weak var delegate : SimilarZHPullDownViewDelegate? 103 | 104 | /// 标签上写的Title 105 | var headerTitle = "上一篇" 106 | var footerTitle = "下一篇" 107 | var title = "Title" 108 | 109 | /// 类型 110 | var type : SimilarZHPullDownType = .middle 111 | 112 | 113 | //MARK: - FUNCTION 114 | override init(frame: CGRect) { 115 | 116 | super.init(frame: frame) 117 | } 118 | 119 | 120 | /** 121 | * 便利构造方法 122 | */ 123 | convenience init(frame: CGRect ,custom:UIView) 124 | { 125 | self.init(frame:frame) 126 | 127 | customView = custom 128 | 129 | addSubview(bottomScrollView) 130 | bottomScrollView.addSubview(headerLabel) 131 | bottomScrollView.addSubview(bottomLabel) 132 | bottomScrollView.addSubview(customView!) 133 | } 134 | 135 | /** 136 | * 便利构造方法 137 | */ 138 | convenience init(custom:UIView) 139 | { 140 | self.init(frame:CGRect.null,custom:custom) 141 | } 142 | 143 | /** 144 | * 便利构造方法 145 | */ 146 | convenience init(custom:UIView,title:String) 147 | { 148 | self.init(custom:custom) 149 | self.title = title 150 | 151 | } 152 | 153 | 154 | required init?(coder aDecoder: NSCoder) 155 | { 156 | super.init(coder:aDecoder) 157 | } 158 | 159 | override func awakeFromNib() { 160 | 161 | } 162 | 163 | override func layoutSubviews() 164 | { 165 | super.layoutSubviews() 166 | 167 | let height = customView?.bounds.height 168 | 169 | let contentHeight = (height! > bounds.height ? height! : bounds.height + 10) 170 | 171 | 172 | bottomScrollView.contentSize = CGSize(width: bounds.width, height: contentHeight) 173 | 174 | //设置显示 175 | headerLabel.text = headerTitle 176 | bottomLabel.text = footerTitle 177 | 178 | 179 | //设置bottom的位置 180 | bottomLabel.frame.origin.y = bottomScrollView.contentSize.height 181 | } 182 | 183 | 184 | /// 创建标签 185 | /// 186 | /// - Parameters: 187 | /// - frame: 188 | /// - title: 标签显示的title 189 | /// - Returns: 190 | func createLable(_ frame:CGRect,title:String) -> UILabel 191 | { 192 | let label:UILabel = UILabel(frame: frame) 193 | label.text = title 194 | label.textAlignment = .center 195 | label.font = UIFont.systemFont(ofSize: 12) 196 | return label 197 | } 198 | 199 | 200 | } 201 | 202 | extension SimilarZHPullDownView : UIScrollViewDelegate 203 | { 204 | 205 | func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { 206 | 207 | //获得偏移量 208 | let contentOffsetY = scrollView.contentOffset.y 209 | 210 | // 如果是中间的滑动,不作处理 211 | guard contentOffsetY < -1 * responseHeight || contentOffsetY > scrollView.contentSize.height + responseHeight - scrollView.bounds.size.height else { 212 | 213 | return 214 | } 215 | 216 | 217 | //当前响应的高度,因为下拉,所以响应距离为负数 218 | let beforeHeight = self.responseHeight * (-1) 219 | 220 | if(contentOffsetY < beforeHeight) 221 | { 222 | print("我是DownView,上一页!") 223 | //表示上一页 224 | self.delegate?.similarZHPullDownView(self, pullType: .up) 225 | } 226 | 227 | //偏移量是视图左上角,所以垂直坐标需要-滚动视图的高度 228 | else if(contentOffsetY > (scrollView.contentSize.height - scrollView.bounds.size.height + self.responseHeight)) 229 | { 230 | print("我是DownView,下一页!") 231 | //表示下一页 232 | self.delegate?.similarZHPullDownView(self, pullType: .down) 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /YSimilarZHPullDownDemo/YSimilarZHPullDownView/YSimilarZHPullDownMainView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // YSimilarZHPullDownMainView.swift 3 | // YSimilarZHPullDownDemo 4 | // 5 | // Created by YueWen on 16/3/14. 6 | // Copyright © 2016年 YueWen. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class YSimilarZHPullDownMainView: UIScrollView ,SimilarZHPullDownViewDelegate{ 12 | 13 | 14 | /// 是否添加子视图 15 | var shouldLayoutAddSubViews = true 16 | 17 | /*** 第一篇上划以及最后一篇下滑显示的默认字样,可修改 ***/ 18 | var headerTitle:String = "已是第一篇" 19 | var footerTitle:String = "最后一篇" 20 | 21 | 22 | 23 | /// 存放预览视图的数组,默认为空数组,为存储属性,设置KVO 24 | var pullViews : [SimilarZHPullDownView]? { 25 | 26 | willSet{ 27 | 28 | //进行newValue的转换 29 | newValue!.first?.headerTitle = headerTitle 30 | newValue!.first?.type = .header 31 | 32 | newValue!.last?.footerTitle = footerTitle 33 | newValue!.last?.type = .footer 34 | 35 | self.ritl_pullViews = newValue! 36 | } 37 | } 38 | 39 | 40 | /// 真正用于显示的视图数组 41 | fileprivate var ritl_pullViews : [SimilarZHPullDownView] = [SimilarZHPullDownView]() 42 | 43 | 44 | /// 存放滚动页的主滚动页 45 | lazy var scrollView:UIScrollView = { 46 | 47 | let scrollView : UIScrollView = UIScrollView(frame: CGRect(x: 0,y: self.titleLabel.bounds.height,width: self.bounds.width,height: self.bounds.height - 50 - 64)) 48 | 49 | scrollView.isPagingEnabled = true//分页显示 50 | scrollView.showsVerticalScrollIndicator = false //不显示垂直滚条 51 | scrollView.isScrollEnabled = false //不能滚动 52 | 53 | return scrollView 54 | 55 | }() 56 | 57 | 58 | /// 显示标题的标题 59 | lazy var titleLabel:UILabel = { 60 | 61 | let label:UILabel = UILabel(frame: CGRect(x: 0,y: 0,width: self.bounds.width,height: 50)) 62 | 63 | label.textAlignment = .center 64 | 65 | return label 66 | 67 | }() 68 | 69 | 70 | //MARK: - FUNCTION 71 | 72 | //MARK: - 构造方法 73 | override init(frame: CGRect) 74 | { 75 | super.init(frame: frame) 76 | 77 | addSubview(titleLabel) 78 | addSubview(scrollView) 79 | } 80 | 81 | 82 | required init?(coder aDecoder: NSCoder) 83 | { 84 | super.init(coder: aDecoder) 85 | } 86 | 87 | 88 | 89 | override func layoutSubviews() { 90 | 91 | if shouldLayoutAddSubViews { 92 | 93 | addChildView() 94 | shouldLayoutAddSubViews = false 95 | } 96 | 97 | //设置自身的contentSize 98 | scrollView.contentSize = CGSize(width: bounds.width, height: CGFloat(ritl_pullViews.count) * bounds.height) 99 | 100 | } 101 | 102 | 103 | 104 | 105 | //MARK: - 功能方法 106 | 107 | /** 108 | * 添加子视图 109 | */ 110 | func addChildView() 111 | { 112 | //获取当前视图的高度和宽度 113 | let height = self.bounds.height 114 | let width = self.bounds.width 115 | 116 | 117 | for i in 0 ..< ritl_pullViews.count 118 | { 119 | //获取存储的SimilarZHPullDownView对象 120 | let pullDownView = self.ritl_pullViews[i] 121 | 122 | pullDownView.frame = CGRect(x: 0, y: CGFloat(i) * height, width: width, height: height - 64 - 50) 123 | 124 | //设置代理 125 | pullDownView.delegate = self 126 | 127 | //添加视图 128 | scrollView.addSubview(pullDownView) 129 | } 130 | 131 | titleLabel.text = ritl_pullViews.first?.title 132 | } 133 | 134 | 135 | 136 | 137 | // MARK: - SimilarZHPullDownView Delegate 138 | func similarZHPullDownView(_ similarZHPullDownView: SimilarZHPullDownView, pullType: PullType) 139 | { 140 | //修复pullViews.count == 1 ,the program is terminated 141 | guard ritl_pullViews.count > 1 else { 142 | 143 | return 144 | } 145 | 146 | //获得当前的偏移量 147 | let contentOffset = scrollView.contentOffset 148 | 149 | //获得索引数 150 | let index = ritl_pullViews.index(of: similarZHPullDownView) 151 | 152 | switch pullType 153 | { 154 | case .up: //上翻页 155 | 156 | if similarZHPullDownView.type != .header { 157 | 158 | pullDone(CGFloat(-1), contentOffset: contentOffset, index: index!) 159 | } 160 | 161 | case .down://下翻页 162 | 163 | if similarZHPullDownView.type != .footer { 164 | 165 | pullDone(CGFloat(1), contentOffset: contentOffset, index: index!) 166 | } 167 | } 168 | } 169 | 170 | 171 | 172 | /** 173 | * 滚动操作 174 | */ 175 | func pullDone(_ paramNumber:CGFloat, contentOffset:CGPoint, index:Int) 176 | { 177 | var contentOffset = contentOffset 178 | 179 | contentOffset.y += (paramNumber * bounds.size.height) 180 | 181 | scrollView.setContentOffset(contentOffset, animated: true) 182 | 183 | //显示即将出现的similarZHPullDownView对象的title 184 | titleLabel.text = ritl_pullViews[index + Int(paramNumber)].title 185 | } 186 | 187 | } 188 | --------------------------------------------------------------------------------