├── .gitignore ├── HoverDome └── .DS_Store ├── HoverDome_OC ├── .DS_Store ├── HoverDome_OC.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── HoverDome_OC │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Children1ViewController.h │ ├── Children1ViewController.m │ ├── Children2ViewController.h │ ├── Children2ViewController.m │ ├── Children3ViewController.h │ ├── Children3ViewController.m │ ├── HoverPageViewController.h │ ├── HoverPageViewController.m │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ └── main.m ├── HoverDome_Swift ├── .DS_Store ├── HoverDome.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── HoverDome │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Children1ViewController.swift │ ├── Children2ViewController.swift │ ├── Children3ViewController.swift │ ├── HoverPageViewController.swift │ ├── Info.plist │ ├── ViewController.swift │ └── hover.gif ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | # Package.resolved 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | # Pods/ 50 | 51 | # Carthage 52 | # 53 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 54 | # Carthage/Checkouts 55 | 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | -------------------------------------------------------------------------------- /HoverDome/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiaokeZ/iOS_HoverPageViewController/07fd92abbccea88edf88bb1884ac09c49ea028f4/HoverDome/.DS_Store -------------------------------------------------------------------------------- /HoverDome_OC/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiaokeZ/iOS_HoverPageViewController/07fd92abbccea88edf88bb1884ac09c49ea028f4/HoverDome_OC/.DS_Store -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 84C7C7F622414EB900A33B22 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C7F522414EB900A33B22 /* AppDelegate.m */; }; 11 | 84C7C7F922414EB900A33B22 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C7F822414EB900A33B22 /* ViewController.m */; }; 12 | 84C7C7FC22414EB900A33B22 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84C7C7FA22414EB900A33B22 /* Main.storyboard */; }; 13 | 84C7C7FE22414EBA00A33B22 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84C7C7FD22414EBA00A33B22 /* Assets.xcassets */; }; 14 | 84C7C80122414EBA00A33B22 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 84C7C7FF22414EBA00A33B22 /* LaunchScreen.storyboard */; }; 15 | 84C7C80422414EBA00A33B22 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C80322414EBA00A33B22 /* main.m */; }; 16 | 84C7C80C22414F0700A33B22 /* HoverPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C80B22414F0700A33B22 /* HoverPageViewController.m */; }; 17 | 84C7C80F2243E8B300A33B22 /* Children1ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C80E2243E8B300A33B22 /* Children1ViewController.m */; }; 18 | 84C7C8122243E8C600A33B22 /* Children2ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C8112243E8C600A33B22 /* Children2ViewController.m */; }; 19 | 84C7C8152243E8D800A33B22 /* Children3ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C7C8142243E8D800A33B22 /* Children3ViewController.m */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 84C7C7F122414EB900A33B22 /* HoverDome_OC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HoverDome_OC.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 84C7C7F422414EB900A33B22 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 25 | 84C7C7F522414EB900A33B22 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 26 | 84C7C7F722414EB900A33B22 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 27 | 84C7C7F822414EB900A33B22 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 28 | 84C7C7FB22414EB900A33B22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | 84C7C7FD22414EBA00A33B22 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | 84C7C80022414EBA00A33B22 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | 84C7C80222414EBA00A33B22 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | 84C7C80322414EBA00A33B22 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 84C7C80A22414F0700A33B22 /* HoverPageViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HoverPageViewController.h; sourceTree = ""; }; 34 | 84C7C80B22414F0700A33B22 /* HoverPageViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HoverPageViewController.m; sourceTree = ""; }; 35 | 84C7C80D2243E8B300A33B22 /* Children1ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Children1ViewController.h; sourceTree = ""; }; 36 | 84C7C80E2243E8B300A33B22 /* Children1ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Children1ViewController.m; sourceTree = ""; }; 37 | 84C7C8102243E8C600A33B22 /* Children2ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Children2ViewController.h; sourceTree = ""; }; 38 | 84C7C8112243E8C600A33B22 /* Children2ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Children2ViewController.m; sourceTree = ""; }; 39 | 84C7C8132243E8D800A33B22 /* Children3ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Children3ViewController.h; sourceTree = ""; }; 40 | 84C7C8142243E8D800A33B22 /* Children3ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Children3ViewController.m; sourceTree = ""; }; 41 | /* End PBXFileReference section */ 42 | 43 | /* Begin PBXFrameworksBuildPhase section */ 44 | 84C7C7EE22414EB900A33B22 /* Frameworks */ = { 45 | isa = PBXFrameworksBuildPhase; 46 | buildActionMask = 2147483647; 47 | files = ( 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXFrameworksBuildPhase section */ 52 | 53 | /* Begin PBXGroup section */ 54 | 84C7C7E822414EB900A33B22 = { 55 | isa = PBXGroup; 56 | children = ( 57 | 84C7C7F322414EB900A33B22 /* HoverDome_OC */, 58 | 84C7C7F222414EB900A33B22 /* Products */, 59 | ); 60 | sourceTree = ""; 61 | }; 62 | 84C7C7F222414EB900A33B22 /* Products */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 84C7C7F122414EB900A33B22 /* HoverDome_OC.app */, 66 | ); 67 | name = Products; 68 | sourceTree = ""; 69 | }; 70 | 84C7C7F322414EB900A33B22 /* HoverDome_OC */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 84C7C7F422414EB900A33B22 /* AppDelegate.h */, 74 | 84C7C7F522414EB900A33B22 /* AppDelegate.m */, 75 | 84C7C7F822414EB900A33B22 /* ViewController.m */, 76 | 84C7C7F722414EB900A33B22 /* ViewController.h */, 77 | 84C7C80D2243E8B300A33B22 /* Children1ViewController.h */, 78 | 84C7C80E2243E8B300A33B22 /* Children1ViewController.m */, 79 | 84C7C8102243E8C600A33B22 /* Children2ViewController.h */, 80 | 84C7C8112243E8C600A33B22 /* Children2ViewController.m */, 81 | 84C7C8132243E8D800A33B22 /* Children3ViewController.h */, 82 | 84C7C8142243E8D800A33B22 /* Children3ViewController.m */, 83 | 84C7C80A22414F0700A33B22 /* HoverPageViewController.h */, 84 | 84C7C80B22414F0700A33B22 /* HoverPageViewController.m */, 85 | 84C7C7FA22414EB900A33B22 /* Main.storyboard */, 86 | 84C7C7FD22414EBA00A33B22 /* Assets.xcassets */, 87 | 84C7C7FF22414EBA00A33B22 /* LaunchScreen.storyboard */, 88 | 84C7C80222414EBA00A33B22 /* Info.plist */, 89 | 84C7C80322414EBA00A33B22 /* main.m */, 90 | ); 91 | path = HoverDome_OC; 92 | sourceTree = ""; 93 | }; 94 | /* End PBXGroup section */ 95 | 96 | /* Begin PBXNativeTarget section */ 97 | 84C7C7F022414EB900A33B22 /* HoverDome_OC */ = { 98 | isa = PBXNativeTarget; 99 | buildConfigurationList = 84C7C80722414EBA00A33B22 /* Build configuration list for PBXNativeTarget "HoverDome_OC" */; 100 | buildPhases = ( 101 | 84C7C7ED22414EB900A33B22 /* Sources */, 102 | 84C7C7EE22414EB900A33B22 /* Frameworks */, 103 | 84C7C7EF22414EB900A33B22 /* Resources */, 104 | ); 105 | buildRules = ( 106 | ); 107 | dependencies = ( 108 | ); 109 | name = HoverDome_OC; 110 | productName = HoverDome_OC; 111 | productReference = 84C7C7F122414EB900A33B22 /* HoverDome_OC.app */; 112 | productType = "com.apple.product-type.application"; 113 | }; 114 | /* End PBXNativeTarget section */ 115 | 116 | /* Begin PBXProject section */ 117 | 84C7C7E922414EB900A33B22 /* Project object */ = { 118 | isa = PBXProject; 119 | attributes = { 120 | LastUpgradeCheck = 1010; 121 | ORGANIZATIONNAME = com.etraffic.EasyCharging; 122 | TargetAttributes = { 123 | 84C7C7F022414EB900A33B22 = { 124 | CreatedOnToolsVersion = 10.1; 125 | }; 126 | }; 127 | }; 128 | buildConfigurationList = 84C7C7EC22414EB900A33B22 /* Build configuration list for PBXProject "HoverDome_OC" */; 129 | compatibilityVersion = "Xcode 9.3"; 130 | developmentRegion = en; 131 | hasScannedForEncodings = 0; 132 | knownRegions = ( 133 | en, 134 | Base, 135 | ); 136 | mainGroup = 84C7C7E822414EB900A33B22; 137 | productRefGroup = 84C7C7F222414EB900A33B22 /* Products */; 138 | projectDirPath = ""; 139 | projectRoot = ""; 140 | targets = ( 141 | 84C7C7F022414EB900A33B22 /* HoverDome_OC */, 142 | ); 143 | }; 144 | /* End PBXProject section */ 145 | 146 | /* Begin PBXResourcesBuildPhase section */ 147 | 84C7C7EF22414EB900A33B22 /* Resources */ = { 148 | isa = PBXResourcesBuildPhase; 149 | buildActionMask = 2147483647; 150 | files = ( 151 | 84C7C80122414EBA00A33B22 /* LaunchScreen.storyboard in Resources */, 152 | 84C7C7FE22414EBA00A33B22 /* Assets.xcassets in Resources */, 153 | 84C7C7FC22414EB900A33B22 /* Main.storyboard in Resources */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | /* End PBXResourcesBuildPhase section */ 158 | 159 | /* Begin PBXSourcesBuildPhase section */ 160 | 84C7C7ED22414EB900A33B22 /* Sources */ = { 161 | isa = PBXSourcesBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | 84C7C8122243E8C600A33B22 /* Children2ViewController.m in Sources */, 165 | 84C7C80C22414F0700A33B22 /* HoverPageViewController.m in Sources */, 166 | 84C7C7F922414EB900A33B22 /* ViewController.m in Sources */, 167 | 84C7C80F2243E8B300A33B22 /* Children1ViewController.m in Sources */, 168 | 84C7C80422414EBA00A33B22 /* main.m in Sources */, 169 | 84C7C7F622414EB900A33B22 /* AppDelegate.m in Sources */, 170 | 84C7C8152243E8D800A33B22 /* Children3ViewController.m in Sources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXSourcesBuildPhase section */ 175 | 176 | /* Begin PBXVariantGroup section */ 177 | 84C7C7FA22414EB900A33B22 /* Main.storyboard */ = { 178 | isa = PBXVariantGroup; 179 | children = ( 180 | 84C7C7FB22414EB900A33B22 /* Base */, 181 | ); 182 | name = Main.storyboard; 183 | sourceTree = ""; 184 | }; 185 | 84C7C7FF22414EBA00A33B22 /* LaunchScreen.storyboard */ = { 186 | isa = PBXVariantGroup; 187 | children = ( 188 | 84C7C80022414EBA00A33B22 /* Base */, 189 | ); 190 | name = LaunchScreen.storyboard; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXVariantGroup section */ 194 | 195 | /* Begin XCBuildConfiguration section */ 196 | 84C7C80522414EBA00A33B22 /* Debug */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | ALWAYS_SEARCH_USER_PATHS = NO; 200 | CLANG_ANALYZER_NONNULL = YES; 201 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 202 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 203 | CLANG_CXX_LIBRARY = "libc++"; 204 | CLANG_ENABLE_MODULES = YES; 205 | CLANG_ENABLE_OBJC_ARC = YES; 206 | CLANG_ENABLE_OBJC_WEAK = YES; 207 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_COMMA = YES; 210 | CLANG_WARN_CONSTANT_CONVERSION = YES; 211 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 212 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 213 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 214 | CLANG_WARN_EMPTY_BODY = YES; 215 | CLANG_WARN_ENUM_CONVERSION = YES; 216 | CLANG_WARN_INFINITE_RECURSION = YES; 217 | CLANG_WARN_INT_CONVERSION = YES; 218 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 220 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 221 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 222 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 223 | CLANG_WARN_STRICT_PROTOTYPES = YES; 224 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 225 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 226 | CLANG_WARN_UNREACHABLE_CODE = YES; 227 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 228 | CODE_SIGN_IDENTITY = "iPhone Developer"; 229 | COPY_PHASE_STRIP = NO; 230 | DEBUG_INFORMATION_FORMAT = dwarf; 231 | ENABLE_STRICT_OBJC_MSGSEND = YES; 232 | ENABLE_TESTABILITY = YES; 233 | GCC_C_LANGUAGE_STANDARD = gnu11; 234 | GCC_DYNAMIC_NO_PIC = NO; 235 | GCC_NO_COMMON_BLOCKS = YES; 236 | GCC_OPTIMIZATION_LEVEL = 0; 237 | GCC_PREPROCESSOR_DEFINITIONS = ( 238 | "DEBUG=1", 239 | "$(inherited)", 240 | ); 241 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 242 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 243 | GCC_WARN_UNDECLARED_SELECTOR = YES; 244 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 245 | GCC_WARN_UNUSED_FUNCTION = YES; 246 | GCC_WARN_UNUSED_VARIABLE = YES; 247 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 248 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 249 | MTL_FAST_MATH = YES; 250 | ONLY_ACTIVE_ARCH = YES; 251 | SDKROOT = iphoneos; 252 | }; 253 | name = Debug; 254 | }; 255 | 84C7C80622414EBA00A33B22 /* Release */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_ANALYZER_NONNULL = YES; 260 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 262 | CLANG_CXX_LIBRARY = "libc++"; 263 | CLANG_ENABLE_MODULES = YES; 264 | CLANG_ENABLE_OBJC_ARC = YES; 265 | CLANG_ENABLE_OBJC_WEAK = YES; 266 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 267 | CLANG_WARN_BOOL_CONVERSION = YES; 268 | CLANG_WARN_COMMA = YES; 269 | CLANG_WARN_CONSTANT_CONVERSION = YES; 270 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 272 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 273 | CLANG_WARN_EMPTY_BODY = YES; 274 | CLANG_WARN_ENUM_CONVERSION = YES; 275 | CLANG_WARN_INFINITE_RECURSION = YES; 276 | CLANG_WARN_INT_CONVERSION = YES; 277 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 278 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 279 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 281 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 282 | CLANG_WARN_STRICT_PROTOTYPES = YES; 283 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 284 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 285 | CLANG_WARN_UNREACHABLE_CODE = YES; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | CODE_SIGN_IDENTITY = "iPhone Developer"; 288 | COPY_PHASE_STRIP = NO; 289 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 290 | ENABLE_NS_ASSERTIONS = NO; 291 | ENABLE_STRICT_OBJC_MSGSEND = YES; 292 | GCC_C_LANGUAGE_STANDARD = gnu11; 293 | GCC_NO_COMMON_BLOCKS = YES; 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 301 | MTL_ENABLE_DEBUG_INFO = NO; 302 | MTL_FAST_MATH = YES; 303 | SDKROOT = iphoneos; 304 | VALIDATE_PRODUCT = YES; 305 | }; 306 | name = Release; 307 | }; 308 | 84C7C80822414EBA00A33B22 /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 312 | CODE_SIGN_STYLE = Automatic; 313 | DEVELOPMENT_TEAM = 3548UVUD68; 314 | INFOPLIST_FILE = HoverDome_OC/Info.plist; 315 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 316 | LD_RUNPATH_SEARCH_PATHS = ( 317 | "$(inherited)", 318 | "@executable_path/Frameworks", 319 | ); 320 | PRODUCT_BUNDLE_IDENTIFIER = "HoverDome-OC"; 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | TARGETED_DEVICE_FAMILY = 1; 323 | }; 324 | name = Debug; 325 | }; 326 | 84C7C80922414EBA00A33B22 /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 330 | CODE_SIGN_STYLE = Automatic; 331 | DEVELOPMENT_TEAM = 3548UVUD68; 332 | INFOPLIST_FILE = HoverDome_OC/Info.plist; 333 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 334 | LD_RUNPATH_SEARCH_PATHS = ( 335 | "$(inherited)", 336 | "@executable_path/Frameworks", 337 | ); 338 | PRODUCT_BUNDLE_IDENTIFIER = "HoverDome-OC"; 339 | PRODUCT_NAME = "$(TARGET_NAME)"; 340 | TARGETED_DEVICE_FAMILY = 1; 341 | }; 342 | name = Release; 343 | }; 344 | /* End XCBuildConfiguration section */ 345 | 346 | /* Begin XCConfigurationList section */ 347 | 84C7C7EC22414EB900A33B22 /* Build configuration list for PBXProject "HoverDome_OC" */ = { 348 | isa = XCConfigurationList; 349 | buildConfigurations = ( 350 | 84C7C80522414EBA00A33B22 /* Debug */, 351 | 84C7C80622414EBA00A33B22 /* Release */, 352 | ); 353 | defaultConfigurationIsVisible = 0; 354 | defaultConfigurationName = Release; 355 | }; 356 | 84C7C80722414EBA00A33B22 /* Build configuration list for PBXNativeTarget "HoverDome_OC" */ = { 357 | isa = XCConfigurationList; 358 | buildConfigurations = ( 359 | 84C7C80822414EBA00A33B22 /* Debug */, 360 | 84C7C80922414EBA00A33B22 /* Release */, 361 | ); 362 | defaultConfigurationIsVisible = 0; 363 | defaultConfigurationName = Release; 364 | }; 365 | /* End XCConfigurationList section */ 366 | }; 367 | rootObject = 84C7C7E922414EB900A33B22 /* Project object */; 368 | } 369 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/AppDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import 4 | 5 | @interface AppDelegate : UIResponder 6 | 7 | @property (strong, nonatomic) UIWindow *window; 8 | 9 | 10 | @end 11 | 12 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "AppDelegate.h" 4 | 5 | @interface AppDelegate () 6 | 7 | @end 8 | 9 | @implementation AppDelegate 10 | 11 | 12 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 13 | // Override point for customization after application launch. 14 | return YES; 15 | } 16 | 17 | 18 | - (void)applicationWillResignActive:(UIApplication *)application { 19 | // 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. 20 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 21 | } 22 | 23 | 24 | - (void)applicationDidEnterBackground:(UIApplication *)application { 25 | // 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. 26 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 27 | } 28 | 29 | 30 | - (void)applicationWillEnterForeground:(UIApplication *)application { 31 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 32 | } 33 | 34 | 35 | - (void)applicationDidBecomeActive:(UIApplication *)application { 36 | // 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. 37 | } 38 | 39 | 40 | - (void)applicationWillTerminate:(UIApplication *)application { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/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 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/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 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Children1ViewController.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "HoverPageViewController.h" 4 | 5 | NS_ASSUME_NONNULL_BEGIN 6 | 7 | @interface Children1ViewController : HoverChildViewController 8 | 9 | @end 10 | 11 | NS_ASSUME_NONNULL_END 12 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Children1ViewController.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "Children1ViewController.h" 4 | 5 | @interface Children1ViewController () 6 | @property(nonatomic, strong) UITableView *tableView; 7 | @end 8 | 9 | @implementation Children1ViewController 10 | 11 | - (void)setOffsetY:(CGFloat)offsetY{ 12 | self.tableView.contentOffset = CGPointMake(0, offsetY); 13 | } 14 | 15 | - (CGFloat)offsetY{ 16 | return self.tableView.contentOffset.y; 17 | } 18 | 19 | - (void)setIsCanScroll:(BOOL)isCanScroll{ 20 | if (isCanScroll == YES){ 21 | [self.tableView setContentOffset:CGPointMake(0, self.offsetY) animated:NO]; 22 | } 23 | } 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | _tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain]; 28 | [_tableView registerClass: [UITableViewCell class] forCellReuseIdentifier:@"123"]; 29 | _tableView.dataSource = self; 30 | _tableView.delegate = self; 31 | self.scrollView = _tableView; 32 | [self.view addSubview:_tableView]; 33 | } 34 | 35 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 36 | return 100; 37 | } 38 | 39 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 40 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"123" forIndexPath:indexPath]; 41 | cell.textLabel.text = [NSString stringWithFormat:@"%zd", indexPath.row]; 42 | return cell; 43 | } 44 | 45 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 46 | if ([self.scrollDelegate respondsToSelector:@selector(hoverChildViewController:scrollViewDidScroll:)]){ 47 | [self.scrollDelegate hoverChildViewController:self scrollViewDidScroll:scrollView]; 48 | } 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Children2ViewController.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "HoverPageViewController.h" 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | @interface Children2ViewController : HoverChildViewController 7 | 8 | @end 9 | 10 | NS_ASSUME_NONNULL_END 11 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Children2ViewController.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "Children2ViewController.h" 4 | 5 | @interface Children2ViewController () 6 | @property(nonatomic, strong) UITableView *tableView; 7 | 8 | @end 9 | 10 | @implementation Children2ViewController 11 | 12 | - (void)setOffsetY:(CGFloat)offsetY{ 13 | self.tableView.contentOffset = CGPointMake(0, offsetY); 14 | } 15 | 16 | - (CGFloat)offsetY{ 17 | return self.tableView.contentOffset.y; 18 | } 19 | 20 | - (void)setIsCanScroll:(BOOL)isCanScroll{ 21 | if (isCanScroll == YES){ 22 | [self.tableView setContentOffset:CGPointMake(0, self.offsetY) animated:NO]; 23 | } 24 | } 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | _tableView = [[UITableView alloc]initWithFrame:self.view.bounds style:UITableViewStylePlain]; 29 | [_tableView registerClass: [UITableViewCell class] forCellReuseIdentifier:@"123"]; 30 | _tableView.dataSource = self; 31 | _tableView.delegate = self; 32 | self.scrollView = _tableView; 33 | [self.view addSubview:_tableView]; 34 | } 35 | 36 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 37 | return 100; 38 | } 39 | 40 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 41 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"123" forIndexPath:indexPath]; 42 | cell.textLabel.text = [NSString stringWithFormat:@"%zd", indexPath.row]; 43 | return cell; 44 | } 45 | 46 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 47 | if ([self.scrollDelegate respondsToSelector:@selector(hoverChildViewController:scrollViewDidScroll:)]){ 48 | [self.scrollDelegate hoverChildViewController:self scrollViewDidScroll:scrollView]; 49 | } 50 | } 51 | 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Children3ViewController.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import "HoverPageViewController.h" 4 | NS_ASSUME_NONNULL_BEGIN 5 | 6 | @interface Children3ViewController : HoverChildViewController 7 | 8 | @end 9 | 10 | NS_ASSUME_NONNULL_END 11 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Children3ViewController.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "Children3ViewController.h" 4 | 5 | @interface Children3ViewController () 6 | @property(nonatomic, strong) UICollectionView *collectionView; 7 | @end 8 | 9 | @implementation Children3ViewController 10 | 11 | - (void)setOffsetY:(CGFloat)offsetY{ 12 | self.collectionView.contentOffset = CGPointMake(0, offsetY); 13 | } 14 | 15 | - (CGFloat)offsetY{ 16 | return self.collectionView.contentOffset.y; 17 | } 18 | 19 | - (void)setIsCanScroll:(BOOL)isCanScroll{ 20 | if (isCanScroll == YES){ 21 | [self.collectionView setContentOffset:CGPointMake(0, self.offsetY) animated:NO]; 22 | } 23 | } 24 | 25 | - (void)viewDidLoad { 26 | [super viewDidLoad]; 27 | 28 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; 29 | layout.itemSize = CGSizeMake(100, 100); 30 | layout.scrollDirection = UICollectionViewScrollDirectionVertical; 31 | layout.minimumLineSpacing = 10; 32 | layout.minimumInteritemSpacing = 10; 33 | 34 | _collectionView = [[UICollectionView alloc]initWithFrame:self.view.bounds collectionViewLayout:layout]; 35 | [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"123"]; 36 | _collectionView.dataSource = self; 37 | _collectionView.delegate = self; 38 | self.scrollView = _collectionView; 39 | [self.view addSubview:_collectionView]; 40 | } 41 | 42 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 43 | return 100; 44 | } 45 | 46 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 47 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"123" forIndexPath:indexPath]; 48 | cell.backgroundColor = [UIColor blueColor]; 49 | return cell; 50 | } 51 | 52 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 53 | if ([self.scrollDelegate respondsToSelector:@selector(hoverChildViewController:scrollViewDidScroll:)]){ 54 | [self.scrollDelegate hoverChildViewController:self scrollViewDidScroll:scrollView]; 55 | } 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/HoverPageViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // HoverPageViewController.h 3 | // HoverPageViewController 4 | // 5 | // Created by admin on 2019/2/27 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | @class HoverChildViewController; 14 | @class HoverPageViewController; 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | @protocol HoverChildViewControllerDelegate 18 | @optional 19 | - (void)hoverChildViewController:(HoverChildViewController *)ViewController scrollViewDidScroll:(UIScrollView *)scrollView; 20 | @end 21 | 22 | @protocol HoverPageViewControllerDelegate 23 | @optional 24 | - (void)hoverPageViewController:(HoverPageViewController *)ViewController scrollViewDidScroll:(UIScrollView *)scrollView; 25 | - (void)hoverPageViewController:(HoverPageViewController *)ViewController scrollViewDidEndDecelerating:(UIScrollView *)scrollView; 26 | @end 27 | 28 | @interface HoverChildViewController : UIViewController 29 | @property(nonatomic, assign) CGFloat offsetY; 30 | @property(nonatomic, assign) BOOL isCanScroll; 31 | @property(nonatomic, weak) id scrollDelegate; 32 | @property(nonatomic, strong) UIScrollView *scrollView; 33 | @end 34 | 35 | @interface HoverPageViewController : UIViewController 36 | 37 | - (instancetype)initWithViewControllers:(NSArray *)viewControllers 38 | headerView:(UIView *)headerView 39 | pageTitleView:(UIView *)pageTitleView; 40 | 41 | + (instancetype)viewControllers:(NSArray *)viewControllers 42 | headerView:(UIView *)headerView 43 | pageTitleView:(UIView *)pageTitleView; 44 | 45 | @property(nonatomic, strong, readonly) NSArray *viewControllers; 46 | @property(nonatomic, strong, readonly) UIView *headerView; 47 | @property(nonatomic, strong, readonly) UIView *pageTitleView; 48 | @property(nonatomic, assign, readonly) NSUInteger currentIndex; 49 | @property(nonatomic, weak) id delegate; 50 | 51 | - (void)moveToAtIndex:(NSInteger)index animated:(BOOL)animated; 52 | 53 | @end 54 | 55 | NS_ASSUME_NONNULL_END 56 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/HoverPageViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // HoverPageViewController.m 3 | // HoverPageViewController 4 | // 5 | // Created by admin on 2019/2/27 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "HoverPageViewController.h" 13 | 14 | @implementation HoverChildViewController 15 | 16 | @end 17 | 18 | @interface HoverPageScrollView : UIScrollView 19 | @property(nonatomic, strong) NSArray *scrollViewWhites; 20 | @end 21 | 22 | @implementation HoverPageScrollView 23 | 24 | - (BOOL)touchesShouldCancelInContentView:(UIView *)view{ 25 | return YES; 26 | } 27 | 28 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{ 29 | if (self.scrollViewWhites == nil) return YES; 30 | for (UIScrollView *item in self.scrollViewWhites) { 31 | if (otherGestureRecognizer.view == item){ 32 | return YES; 33 | } 34 | } 35 | return NO; 36 | } 37 | @end 38 | 39 | @interface HoverPageViewController () 40 | @property(nonatomic, strong) HoverPageScrollView *mainScrollView; 41 | @property(nonatomic, strong) UIScrollView *pageScrollView; 42 | @end 43 | 44 | @implementation HoverPageViewController 45 | 46 | - (instancetype)initWithViewControllers:(NSArray *)viewControllers 47 | headerView:(UIView *)headerView 48 | pageTitleView:(UIView *)pageTitleView{ 49 | if (self = [super initWithNibName:nil bundle:nil]){ 50 | _viewControllers = viewControllers; 51 | _headerView = headerView; 52 | _pageTitleView = pageTitleView; 53 | } 54 | return self; 55 | } 56 | 57 | + (instancetype)viewControllers:(NSArray *)viewControllers 58 | headerView:(UIView *)headerView 59 | pageTitleView:(UIView *)pageTitleView{ 60 | return [[HoverPageViewController alloc]initWithViewControllers:viewControllers headerView:headerView pageTitleView:pageTitleView]; 61 | } 62 | 63 | - (void)viewDidLoad { 64 | [super viewDidLoad]; 65 | [self prepareView]; 66 | } 67 | 68 | - (void)prepareView{ 69 | self.mainScrollView = [[HoverPageScrollView alloc]init]; 70 | self.mainScrollView.bounces = NO; 71 | self.mainScrollView.delegate = self; 72 | self.mainScrollView.showsVerticalScrollIndicator = NO; 73 | [self.view addSubview:self.mainScrollView]; 74 | [self.mainScrollView addSubview:_headerView]; 75 | [self.mainScrollView addSubview:_pageTitleView]; 76 | 77 | self.pageScrollView = [[UIScrollView alloc]init]; 78 | self.pageScrollView.pagingEnabled = YES; 79 | self.pageScrollView.delegate = self; 80 | self.pageScrollView.showsHorizontalScrollIndicator = NO; 81 | [self.mainScrollView addSubview:self.pageScrollView]; 82 | for (HoverPageViewController *vc in self.viewControllers) { 83 | [self.pageScrollView addSubview:vc.view]; 84 | [self addChildViewController:vc]; 85 | } 86 | if (@available(iOS 11.0, *)){ 87 | self.mainScrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 88 | }else{ 89 | self.automaticallyAdjustsScrollViewInsets = NO; 90 | } 91 | } 92 | 93 | - (void)viewDidLayoutSubviews{ 94 | [super viewDidLayoutSubviews]; 95 | self.mainScrollView.frame = self.view.bounds; 96 | self.mainScrollView.contentSize = CGSizeMake(0, self.mainScrollView.frame.size.height + self.headerView.frame.size.height); 97 | _pageTitleView.frame = CGRectMake(0, CGRectGetMaxY(_headerView.frame), _pageTitleView.frame.size.width, _pageTitleView.frame.size.height); 98 | self.pageScrollView.frame = CGRectMake(0, CGRectGetMaxY(_pageTitleView.frame), self.view.frame.size.width, self.mainScrollView.contentSize.height - CGRectGetMaxY(_pageTitleView.frame)); 99 | self.pageScrollView.contentSize = CGSizeMake(self.view.frame.size.width * _viewControllers.count, 0); 100 | NSMutableArray *scrollViews = [NSMutableArray array]; 101 | for (NSInteger i = 0; i < _viewControllers.count; i++) { 102 | HoverChildViewController *child = [_viewControllers objectAtIndex:i]; 103 | child.scrollDelegate = self; 104 | child.view.frame = CGRectMake(i * self.view.frame.size.width, child.view.frame.origin.y, child.view.frame.size.width, child.view.frame.size.height); 105 | if (child.scrollView != nil){ 106 | [scrollViews addObject:child.scrollView]; 107 | child.scrollView.frame = CGRectMake(child.scrollView.frame.origin.x, child.scrollView.frame.origin.y, child.scrollView.frame.size.width, self.pageScrollView.frame.size.height); 108 | } 109 | } 110 | self.mainScrollView.scrollViewWhites = scrollViews; 111 | } 112 | 113 | - (void)moveToAtIndex:(NSInteger)index animated:(BOOL)animated{ 114 | for (HoverChildViewController *child in _viewControllers) { 115 | child.isCanScroll = YES; 116 | } 117 | [self.pageScrollView setContentOffset:CGPointMake(index * self.view.frame.size.width, 0) animated:animated]; 118 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 119 | [self scrollViewDidEndDecelerating:self.pageScrollView]; 120 | }); 121 | } 122 | 123 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ 124 | self.pageScrollView.scrollEnabled = YES; 125 | self.mainScrollView.scrollEnabled = YES; 126 | } 127 | 128 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ 129 | self.pageScrollView.scrollEnabled = YES; 130 | self.mainScrollView.scrollEnabled = YES; 131 | if (scrollView == self.pageScrollView){ 132 | _currentIndex = (NSUInteger)(scrollView.contentOffset.x / scrollView.frame.size.width + 0.5) % _viewControllers.count; 133 | if ([self.delegate respondsToSelector:@selector(hoverPageViewController:scrollViewDidEndDecelerating:)]){ 134 | [self.delegate hoverPageViewController:self scrollViewDidEndDecelerating:scrollView]; 135 | } 136 | } 137 | } 138 | 139 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 140 | if (scrollView == self.mainScrollView){ 141 | self.pageScrollView.scrollEnabled = NO; 142 | HoverChildViewController *child = [_viewControllers objectAtIndex:_currentIndex]; 143 | if (child.offsetY > 0){ 144 | scrollView.contentOffset = CGPointMake(0, self.headerView.frame.size.height); 145 | }else{ 146 | for (HoverChildViewController *child in _viewControllers) { 147 | child.offsetY = 0; 148 | } 149 | } 150 | }else if (scrollView == self.pageScrollView){ 151 | self.mainScrollView.scrollEnabled = NO; 152 | if ([self.delegate respondsToSelector:@selector(hoverPageViewController:scrollViewDidScroll:)]){ 153 | [self.delegate hoverPageViewController:self scrollViewDidScroll:scrollView]; 154 | } 155 | } 156 | } 157 | 158 | - (void)hoverChildViewController:(HoverChildViewController *)ViewController scrollViewDidScroll:(UIScrollView *)scrollView{ 159 | if (self.mainScrollView.contentOffset.y < self.headerView.frame.size.height && self.mainScrollView.contentOffset.y > 0){ 160 | HoverChildViewController *child = [_viewControllers objectAtIndex:_currentIndex]; 161 | child.offsetY = 0; 162 | } 163 | } 164 | 165 | @end 166 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/ViewController.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import 4 | 5 | @interface ViewController : UIViewController 6 | 7 | 8 | @end 9 | 10 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/ViewController.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import "ViewController.h" 4 | #import "HoverPageViewController.h" 5 | #import "Children1ViewController.h" 6 | #import "Children2ViewController.h" 7 | #import "Children3ViewController.h" 8 | @interface ViewController () 9 | @property(nonatomic, strong) UIView *indicator; 10 | @property(nonatomic, strong) HoverPageViewController *hoverPageViewController; 11 | @end 12 | 13 | @implementation ViewController 14 | 15 | - (void)viewDidLoad { 16 | [super viewDidLoad]; 17 | self.title = @"悬停"; 18 | 19 | UILabel *headerView = [UILabel new]; 20 | headerView.frame = CGRectMake(0, 0, self.view.frame.size.width, 200); 21 | headerView.text = @"可上下滑动头部"; 22 | headerView.textColor = [UIColor whiteColor]; 23 | headerView.backgroundColor = [UIColor redColor]; 24 | headerView.textAlignment = NSTextAlignmentCenter; 25 | 26 | /// 指示器 27 | UIView *pageTitleView = [UIView new]; 28 | pageTitleView.backgroundColor = [UIColor lightGrayColor]; 29 | pageTitleView.frame = CGRectMake(0, 0, self.view.frame.size.width, 40); 30 | 31 | /// 添加3个按钮 32 | CGSize buttonSize = CGSizeMake(self.view.frame.size.width / 3, pageTitleView.frame.size.height); 33 | for (int i = 0; i < 3; i++) { 34 | UIButton *button = [UIButton new]; 35 | button.tag = i; 36 | [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside]; 37 | button.frame = CGRectMake(i * buttonSize.width, 0, buttonSize.width, buttonSize.height); 38 | [button setTitle:@"控制器" forState:UIControlStateNormal]; 39 | [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 40 | [pageTitleView addSubview:button]; 41 | } 42 | 43 | UIButton *button = pageTitleView.subviews.firstObject; 44 | [button layoutIfNeeded]; 45 | 46 | /// 指示器底部 47 | self.indicator = [UIView new]; 48 | self.indicator.frame = CGRectMake(0, buttonSize.height - 3, buttonSize.width, 3); 49 | self.indicator.backgroundColor = [UIColor yellowColor]; 50 | [pageTitleView addSubview: self.indicator]; 51 | 52 | /// 添加子控制器 53 | NSMutableArray *viewControllers = [NSMutableArray array]; 54 | HoverChildViewController *vc1 = [[Children1ViewController alloc]init]; 55 | HoverChildViewController *vc2 = [[Children2ViewController alloc]init]; 56 | HoverChildViewController *vc3 = [[Children3ViewController alloc]init]; 57 | [viewControllers addObject:vc1]; 58 | [viewControllers addObject:vc2]; 59 | [viewControllers addObject:vc3]; 60 | 61 | /// 计算导航栏高度 62 | CGFloat barHeight = [UIApplication sharedApplication].statusBarFrame.size.height + self.navigationController.navigationBar.frame.size.height; 63 | 64 | /// 添加分页控制器 65 | self.hoverPageViewController = [HoverPageViewController viewControllers:viewControllers headerView:headerView pageTitleView:pageTitleView]; 66 | self.hoverPageViewController.view.frame = CGRectMake(0, barHeight, self.view.frame.size.width, self.view.frame.size.height - barHeight); 67 | self.hoverPageViewController.delegate = self; 68 | [self addChildViewController:self.hoverPageViewController]; 69 | [self.view addSubview:self.hoverPageViewController.view]; 70 | } 71 | 72 | - (void)buttonClick:(UIButton *)btn{ 73 | [self.hoverPageViewController moveToAtIndex:btn.tag animated:YES]; 74 | } 75 | 76 | - (void)hoverPageViewController:(HoverPageViewController *)ViewController scrollViewDidScroll:(UIScrollView *)scrollView{ 77 | CGFloat progress = scrollView.contentOffset.x / scrollView.frame.size.width; 78 | self.indicator.frame = CGRectMake(self.indicator.frame.size.width * progress, self.indicator.frame.origin.y, self.indicator.frame.size.width, self.indicator.frame.size.height); 79 | 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /HoverDome_OC/HoverDome_OC/main.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | #import 4 | #import "AppDelegate.h" 5 | 6 | int main(int argc, char * argv[]) { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /HoverDome_Swift/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiaokeZ/iOS_HoverPageViewController/07fd92abbccea88edf88bb1884ac09c49ea028f4/HoverDome_Swift/.DS_Store -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 846C4CD722263DE4008C6AC1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C4CD622263DE4008C6AC1 /* AppDelegate.swift */; }; 11 | 846C4CD922263DE4008C6AC1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C4CD822263DE4008C6AC1 /* ViewController.swift */; }; 12 | 846C4CDC22263DE4008C6AC1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 846C4CDA22263DE4008C6AC1 /* Main.storyboard */; }; 13 | 846C4CDE22263DEC008C6AC1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 846C4CDD22263DEC008C6AC1 /* Assets.xcassets */; }; 14 | 846C4CE122263DEC008C6AC1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 846C4CDF22263DEC008C6AC1 /* LaunchScreen.storyboard */; }; 15 | 846C4CE922263E27008C6AC1 /* Children1ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C4CE822263E27008C6AC1 /* Children1ViewController.swift */; }; 16 | 846C4CEB22263E35008C6AC1 /* Children2ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C4CEA22263E35008C6AC1 /* Children2ViewController.swift */; }; 17 | 846C4CED22263E3F008C6AC1 /* Children3ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C4CEC22263E3F008C6AC1 /* Children3ViewController.swift */; }; 18 | 846C4CF1222775FA008C6AC1 /* HoverPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C4CF0222775FA008C6AC1 /* HoverPageViewController.swift */; }; 19 | 846C4CF92227C6F1008C6AC1 /* hover.gif in Resources */ = {isa = PBXBuildFile; fileRef = 846C4CF82227C6F1008C6AC1 /* hover.gif */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 846C4CD322263DE4008C6AC1 /* HoverDome.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HoverDome.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 846C4CD622263DE4008C6AC1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 25 | 846C4CD822263DE4008C6AC1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 26 | 846C4CDB22263DE4008C6AC1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 27 | 846C4CDD22263DEC008C6AC1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 28 | 846C4CE022263DEC008C6AC1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 29 | 846C4CE222263DEC008C6AC1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | 846C4CE822263E27008C6AC1 /* Children1ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Children1ViewController.swift; sourceTree = ""; }; 31 | 846C4CEA22263E35008C6AC1 /* Children2ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Children2ViewController.swift; sourceTree = ""; }; 32 | 846C4CEC22263E3F008C6AC1 /* Children3ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Children3ViewController.swift; sourceTree = ""; }; 33 | 846C4CF0222775FA008C6AC1 /* HoverPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverPageViewController.swift; sourceTree = ""; }; 34 | 846C4CF82227C6F1008C6AC1 /* hover.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = hover.gif; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 846C4CD022263DE4008C6AC1 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | 846C4CCA22263DE4008C6AC1 = { 49 | isa = PBXGroup; 50 | children = ( 51 | 846C4CD522263DE4008C6AC1 /* HoverDome */, 52 | 846C4CD422263DE4008C6AC1 /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 846C4CD422263DE4008C6AC1 /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 846C4CD322263DE4008C6AC1 /* HoverDome.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 846C4CD522263DE4008C6AC1 /* HoverDome */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 846C4CF82227C6F1008C6AC1 /* hover.gif */, 68 | 846C4CD822263DE4008C6AC1 /* ViewController.swift */, 69 | 846C4CE822263E27008C6AC1 /* Children1ViewController.swift */, 70 | 846C4CEA22263E35008C6AC1 /* Children2ViewController.swift */, 71 | 846C4CEC22263E3F008C6AC1 /* Children3ViewController.swift */, 72 | 846C4CF0222775FA008C6AC1 /* HoverPageViewController.swift */, 73 | 846C4CD622263DE4008C6AC1 /* AppDelegate.swift */, 74 | 846C4CDA22263DE4008C6AC1 /* Main.storyboard */, 75 | 846C4CDD22263DEC008C6AC1 /* Assets.xcassets */, 76 | 846C4CDF22263DEC008C6AC1 /* LaunchScreen.storyboard */, 77 | 846C4CE222263DEC008C6AC1 /* Info.plist */, 78 | ); 79 | path = HoverDome; 80 | sourceTree = ""; 81 | }; 82 | /* End PBXGroup section */ 83 | 84 | /* Begin PBXNativeTarget section */ 85 | 846C4CD222263DE4008C6AC1 /* HoverDome */ = { 86 | isa = PBXNativeTarget; 87 | buildConfigurationList = 846C4CE522263DEC008C6AC1 /* Build configuration list for PBXNativeTarget "HoverDome" */; 88 | buildPhases = ( 89 | 846C4CCF22263DE4008C6AC1 /* Sources */, 90 | 846C4CD022263DE4008C6AC1 /* Frameworks */, 91 | 846C4CD122263DE4008C6AC1 /* Resources */, 92 | ); 93 | buildRules = ( 94 | ); 95 | dependencies = ( 96 | ); 97 | name = HoverDome; 98 | productName = HoverDome; 99 | productReference = 846C4CD322263DE4008C6AC1 /* HoverDome.app */; 100 | productType = "com.apple.product-type.application"; 101 | }; 102 | /* End PBXNativeTarget section */ 103 | 104 | /* Begin PBXProject section */ 105 | 846C4CCB22263DE4008C6AC1 /* Project object */ = { 106 | isa = PBXProject; 107 | attributes = { 108 | LastSwiftUpdateCheck = 1010; 109 | LastUpgradeCheck = 1010; 110 | ORGANIZATIONNAME = zhouqiao; 111 | TargetAttributes = { 112 | 846C4CD222263DE4008C6AC1 = { 113 | CreatedOnToolsVersion = 10.1; 114 | }; 115 | }; 116 | }; 117 | buildConfigurationList = 846C4CCE22263DE4008C6AC1 /* Build configuration list for PBXProject "HoverDome" */; 118 | compatibilityVersion = "Xcode 9.3"; 119 | developmentRegion = en; 120 | hasScannedForEncodings = 0; 121 | knownRegions = ( 122 | en, 123 | Base, 124 | ); 125 | mainGroup = 846C4CCA22263DE4008C6AC1; 126 | productRefGroup = 846C4CD422263DE4008C6AC1 /* Products */; 127 | projectDirPath = ""; 128 | projectRoot = ""; 129 | targets = ( 130 | 846C4CD222263DE4008C6AC1 /* HoverDome */, 131 | ); 132 | }; 133 | /* End PBXProject section */ 134 | 135 | /* Begin PBXResourcesBuildPhase section */ 136 | 846C4CD122263DE4008C6AC1 /* Resources */ = { 137 | isa = PBXResourcesBuildPhase; 138 | buildActionMask = 2147483647; 139 | files = ( 140 | 846C4CE122263DEC008C6AC1 /* LaunchScreen.storyboard in Resources */, 141 | 846C4CF92227C6F1008C6AC1 /* hover.gif in Resources */, 142 | 846C4CDE22263DEC008C6AC1 /* Assets.xcassets in Resources */, 143 | 846C4CDC22263DE4008C6AC1 /* Main.storyboard in Resources */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXResourcesBuildPhase section */ 148 | 149 | /* Begin PBXSourcesBuildPhase section */ 150 | 846C4CCF22263DE4008C6AC1 /* Sources */ = { 151 | isa = PBXSourcesBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | 846C4CF1222775FA008C6AC1 /* HoverPageViewController.swift in Sources */, 155 | 846C4CED22263E3F008C6AC1 /* Children3ViewController.swift in Sources */, 156 | 846C4CE922263E27008C6AC1 /* Children1ViewController.swift in Sources */, 157 | 846C4CD922263DE4008C6AC1 /* ViewController.swift in Sources */, 158 | 846C4CEB22263E35008C6AC1 /* Children2ViewController.swift in Sources */, 159 | 846C4CD722263DE4008C6AC1 /* AppDelegate.swift in Sources */, 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXSourcesBuildPhase section */ 164 | 165 | /* Begin PBXVariantGroup section */ 166 | 846C4CDA22263DE4008C6AC1 /* Main.storyboard */ = { 167 | isa = PBXVariantGroup; 168 | children = ( 169 | 846C4CDB22263DE4008C6AC1 /* Base */, 170 | ); 171 | name = Main.storyboard; 172 | sourceTree = ""; 173 | }; 174 | 846C4CDF22263DEC008C6AC1 /* LaunchScreen.storyboard */ = { 175 | isa = PBXVariantGroup; 176 | children = ( 177 | 846C4CE022263DEC008C6AC1 /* Base */, 178 | ); 179 | name = LaunchScreen.storyboard; 180 | sourceTree = ""; 181 | }; 182 | /* End PBXVariantGroup section */ 183 | 184 | /* Begin XCBuildConfiguration section */ 185 | 846C4CE322263DEC008C6AC1 /* Debug */ = { 186 | isa = XCBuildConfiguration; 187 | buildSettings = { 188 | ALWAYS_SEARCH_USER_PATHS = NO; 189 | CLANG_ANALYZER_NONNULL = YES; 190 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 191 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 192 | CLANG_CXX_LIBRARY = "libc++"; 193 | CLANG_ENABLE_MODULES = YES; 194 | CLANG_ENABLE_OBJC_ARC = YES; 195 | CLANG_ENABLE_OBJC_WEAK = YES; 196 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 197 | CLANG_WARN_BOOL_CONVERSION = YES; 198 | CLANG_WARN_COMMA = YES; 199 | CLANG_WARN_CONSTANT_CONVERSION = YES; 200 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 201 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 202 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 203 | CLANG_WARN_EMPTY_BODY = YES; 204 | CLANG_WARN_ENUM_CONVERSION = YES; 205 | CLANG_WARN_INFINITE_RECURSION = YES; 206 | CLANG_WARN_INT_CONVERSION = YES; 207 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 208 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 209 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 210 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 211 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 212 | CLANG_WARN_STRICT_PROTOTYPES = YES; 213 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 214 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 215 | CLANG_WARN_UNREACHABLE_CODE = YES; 216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 217 | CODE_SIGN_IDENTITY = "iPhone Developer"; 218 | COPY_PHASE_STRIP = NO; 219 | DEBUG_INFORMATION_FORMAT = dwarf; 220 | ENABLE_STRICT_OBJC_MSGSEND = YES; 221 | ENABLE_TESTABILITY = YES; 222 | GCC_C_LANGUAGE_STANDARD = gnu11; 223 | GCC_DYNAMIC_NO_PIC = NO; 224 | GCC_NO_COMMON_BLOCKS = YES; 225 | GCC_OPTIMIZATION_LEVEL = 0; 226 | GCC_PREPROCESSOR_DEFINITIONS = ( 227 | "DEBUG=1", 228 | "$(inherited)", 229 | ); 230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 237 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 238 | MTL_FAST_MATH = YES; 239 | ONLY_ACTIVE_ARCH = YES; 240 | SDKROOT = iphoneos; 241 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 242 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 243 | }; 244 | name = Debug; 245 | }; 246 | 846C4CE422263DEC008C6AC1 /* Release */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_SEARCH_USER_PATHS = NO; 250 | CLANG_ANALYZER_NONNULL = YES; 251 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 252 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 253 | CLANG_CXX_LIBRARY = "libc++"; 254 | CLANG_ENABLE_MODULES = YES; 255 | CLANG_ENABLE_OBJC_ARC = YES; 256 | CLANG_ENABLE_OBJC_WEAK = YES; 257 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 258 | CLANG_WARN_BOOL_CONVERSION = YES; 259 | CLANG_WARN_COMMA = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 262 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 263 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INFINITE_RECURSION = YES; 267 | CLANG_WARN_INT_CONVERSION = YES; 268 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 269 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 270 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 271 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 272 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 273 | CLANG_WARN_STRICT_PROTOTYPES = YES; 274 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 275 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 276 | CLANG_WARN_UNREACHABLE_CODE = YES; 277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 278 | CODE_SIGN_IDENTITY = "iPhone Developer"; 279 | COPY_PHASE_STRIP = NO; 280 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 281 | ENABLE_NS_ASSERTIONS = NO; 282 | ENABLE_STRICT_OBJC_MSGSEND = YES; 283 | GCC_C_LANGUAGE_STANDARD = gnu11; 284 | GCC_NO_COMMON_BLOCKS = YES; 285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 287 | GCC_WARN_UNDECLARED_SELECTOR = YES; 288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 289 | GCC_WARN_UNUSED_FUNCTION = YES; 290 | GCC_WARN_UNUSED_VARIABLE = YES; 291 | IPHONEOS_DEPLOYMENT_TARGET = 12.1; 292 | MTL_ENABLE_DEBUG_INFO = NO; 293 | MTL_FAST_MATH = YES; 294 | SDKROOT = iphoneos; 295 | SWIFT_COMPILATION_MODE = wholemodule; 296 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 297 | VALIDATE_PRODUCT = YES; 298 | }; 299 | name = Release; 300 | }; 301 | 846C4CE622263DEC008C6AC1 /* Debug */ = { 302 | isa = XCBuildConfiguration; 303 | buildSettings = { 304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 305 | CODE_SIGN_STYLE = Automatic; 306 | DEVELOPMENT_TEAM = 3548UVUD68; 307 | INFOPLIST_FILE = HoverDome/Info.plist; 308 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 309 | LD_RUNPATH_SEARCH_PATHS = ( 310 | "$(inherited)", 311 | "@executable_path/Frameworks", 312 | ); 313 | PRODUCT_BUNDLE_IDENTIFIER = "-23.HoverDome"; 314 | PRODUCT_NAME = "$(TARGET_NAME)"; 315 | SWIFT_VERSION = 4.2; 316 | TARGETED_DEVICE_FAMILY = 1; 317 | }; 318 | name = Debug; 319 | }; 320 | 846C4CE722263DEC008C6AC1 /* Release */ = { 321 | isa = XCBuildConfiguration; 322 | buildSettings = { 323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 324 | CODE_SIGN_STYLE = Automatic; 325 | DEVELOPMENT_TEAM = 3548UVUD68; 326 | INFOPLIST_FILE = HoverDome/Info.plist; 327 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 328 | LD_RUNPATH_SEARCH_PATHS = ( 329 | "$(inherited)", 330 | "@executable_path/Frameworks", 331 | ); 332 | PRODUCT_BUNDLE_IDENTIFIER = "-23.HoverDome"; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | SWIFT_VERSION = 4.2; 335 | TARGETED_DEVICE_FAMILY = 1; 336 | }; 337 | name = Release; 338 | }; 339 | /* End XCBuildConfiguration section */ 340 | 341 | /* Begin XCConfigurationList section */ 342 | 846C4CCE22263DE4008C6AC1 /* Build configuration list for PBXProject "HoverDome" */ = { 343 | isa = XCConfigurationList; 344 | buildConfigurations = ( 345 | 846C4CE322263DEC008C6AC1 /* Debug */, 346 | 846C4CE422263DEC008C6AC1 /* Release */, 347 | ); 348 | defaultConfigurationIsVisible = 0; 349 | defaultConfigurationName = Release; 350 | }; 351 | 846C4CE522263DEC008C6AC1 /* Build configuration list for PBXNativeTarget "HoverDome" */ = { 352 | isa = XCConfigurationList; 353 | buildConfigurations = ( 354 | 846C4CE622263DEC008C6AC1 /* Debug */, 355 | 846C4CE722263DEC008C6AC1 /* Release */, 356 | ); 357 | defaultConfigurationIsVisible = 0; 358 | defaultConfigurationName = Release; 359 | }; 360 | /* End XCConfigurationList section */ 361 | }; 362 | rootObject = 846C4CCB22263DE4008C6AC1 /* Project object */; 363 | } 364 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // HoverDome 4 | // 5 | // Created by admin on 2019/2/27. 6 | // Copyright © 2019 zhouqiao. 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: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/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 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/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 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/Children1ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Children1ViewController.swift 3 | // HoverDome 4 | // 5 | // Created by admin on 2019/2/27. 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class Children1ViewController: HoverChildViewController { 12 | 13 | private var tableView:UITableView! 14 | private lazy var items: [String] = { 15 | var items = [String]() 16 | for i in 0..<100 { 17 | items.append("\(i)") 18 | } 19 | return items 20 | }() 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | view.backgroundColor = UIColor.green 25 | 26 | tableView = UITableView(frame: view.bounds, style: .plain) 27 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "aaaa") 28 | tableView.delegate = self 29 | tableView.dataSource = self 30 | view.addSubview(tableView) 31 | scrollView = tableView 32 | } 33 | 34 | override var offsetY: CGFloat{ 35 | set{ 36 | tableView.contentOffset = CGPoint(x: 0, y: newValue) 37 | } 38 | get{ 39 | return tableView.contentOffset.y 40 | } 41 | } 42 | 43 | override var isCanScroll: Bool{ 44 | didSet{ 45 | if isCanScroll{ 46 | tableView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: false) 47 | } 48 | } 49 | } 50 | } 51 | 52 | extension Children1ViewController: UITableViewDataSource, UITableViewDelegate { 53 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 54 | return items.count 55 | } 56 | 57 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 58 | let cell = tableView.dequeueReusableCell(withIdentifier: "aaaa", for: indexPath) 59 | cell.textLabel?.text = items[indexPath.row] 60 | return cell 61 | } 62 | 63 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 64 | tableView.deselectRow(at: indexPath, animated: true) 65 | let vc = UIViewController() 66 | navigationController?.pushViewController(vc, animated: true) 67 | 68 | } 69 | 70 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 71 | scrollDelegate?.hoverChildViewController(self, scrollViewDidScroll: scrollView) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/Children2ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Children2ViewController.swift 3 | // HoverDome 4 | // 5 | // Created by admin on 2019/2/27. 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class Children2ViewController: HoverChildViewController { 12 | 13 | private var tableView:UITableView! 14 | private lazy var items: [String] = { 15 | var items = [String]() 16 | for i in 0..<100 { 17 | items.append("\(i)") 18 | } 19 | return items 20 | }() 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | view.backgroundColor = UIColor.green 25 | 26 | tableView = UITableView(frame: view.bounds, style: .plain) 27 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "aaaa") 28 | tableView.delegate = self 29 | tableView.dataSource = self 30 | view.addSubview(tableView) 31 | scrollView = tableView 32 | } 33 | 34 | override var offsetY: CGFloat{ 35 | set{ 36 | tableView.contentOffset = CGPoint(x: 0, y: newValue) 37 | } 38 | get{ 39 | return tableView.contentOffset.y 40 | } 41 | } 42 | 43 | override var isCanScroll: Bool{ 44 | didSet{ 45 | if isCanScroll{ 46 | tableView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: false) 47 | } 48 | } 49 | } 50 | } 51 | 52 | extension Children2ViewController: UITableViewDataSource, UITableViewDelegate { 53 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 54 | return items.count 55 | } 56 | 57 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 58 | let cell = tableView.dequeueReusableCell(withIdentifier: "aaaa", for: indexPath) 59 | cell.textLabel?.text = items[indexPath.row] 60 | return cell 61 | } 62 | 63 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 64 | tableView.deselectRow(at: indexPath, animated: true) 65 | } 66 | 67 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 68 | scrollDelegate?.hoverChildViewController(self, scrollViewDidScroll: scrollView) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/Children3ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Children3ViewController.swift 3 | // HoverDome 4 | // 5 | // Created by admin on 2019/2/27. 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class Children3ViewController: HoverChildViewController { 12 | 13 | private var collectionView:UICollectionView! 14 | private lazy var items: [String] = { 15 | var items = [String]() 16 | for i in 0..<100 { 17 | items.append("\(i)") 18 | } 19 | return items 20 | }() 21 | 22 | override func viewDidLoad() { 23 | super.viewDidLoad() 24 | view.backgroundColor = UIColor.yellow 25 | 26 | let layout = UICollectionViewFlowLayout() 27 | layout.itemSize = CGSize(width: 100, height: 100) 28 | layout.scrollDirection = .vertical 29 | layout.minimumLineSpacing = 5 30 | layout.minimumInteritemSpacing = 5 31 | 32 | collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout) 33 | collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "aaa") 34 | collectionView.dataSource = self 35 | collectionView.delegate = self 36 | view.addSubview(collectionView) 37 | scrollView = collectionView 38 | } 39 | 40 | override var offsetY: CGFloat{ 41 | set{ 42 | collectionView.contentOffset = CGPoint(x: 0, y: newValue) 43 | } 44 | get{ 45 | return collectionView.contentOffset.y 46 | } 47 | } 48 | 49 | override var isCanScroll: Bool{ 50 | didSet{ 51 | if isCanScroll{ 52 | collectionView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: false) 53 | } 54 | } 55 | } 56 | } 57 | 58 | extension Children3ViewController: UICollectionViewDataSource, UICollectionViewDelegate { 59 | 60 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 61 | return items.count 62 | } 63 | 64 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 65 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "aaa", for: indexPath) 66 | cell.backgroundColor = UIColor.blue 67 | return cell 68 | } 69 | 70 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 71 | scrollDelegate?.hoverChildViewController(self, scrollViewDidScroll: scrollView) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/HoverPageViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HoverPageViewController.swift 3 | // HoverPageViewController 4 | // 5 | // Created by admin on 2019/2/27 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | import UIKit 13 | 14 | protocol HoverChildViewControllerDelegate: NSObjectProtocol { 15 | func hoverChildViewController(_ viewController: HoverChildViewController, scrollViewDidScroll scrollView: UIScrollView) 16 | } 17 | 18 | protocol HoverPageViewControllerDelegate: NSObjectProtocol { 19 | func hoverPageViewController(_ viewController: HoverPageViewController, scrollViewDidScroll scrollView: UIScrollView) 20 | func hoverPageViewController(_ viewController: HoverPageViewController, scrollViewDidEndDecelerating scrollView: UIScrollView) 21 | } 22 | 23 | class HoverChildViewController: UIViewController { 24 | 25 | public var offsetY: CGFloat = 0.0 26 | public var isCanScroll: Bool = false 27 | public weak var scrollDelegate: HoverChildViewControllerDelegate? 28 | public var scrollView:UIScrollView? 29 | } 30 | 31 | class HoverPageScrollView: UIScrollView, UIGestureRecognizerDelegate { 32 | 33 | public var scrollViewWhites: Set? 34 | 35 | override func touchesShouldCancel(in view: UIView) -> Bool { 36 | return true 37 | } 38 | 39 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { 40 | guard let scrollViewWhites = scrollViewWhites else { return true } 41 | for item in scrollViewWhites { 42 | if let view = otherGestureRecognizer.view, view == item { 43 | return true 44 | } 45 | } 46 | return false 47 | } 48 | } 49 | 50 | class HoverPageViewController: UIViewController { 51 | 52 | weak var delegate: HoverPageViewControllerDelegate? 53 | 54 | private(set) var viewControllers = [HoverChildViewController]() 55 | private(set) var headerView: UIView! 56 | private(set) var pageTitleView: UIView! 57 | private(set) var currentIndex: Int = 0 58 | private var mainScrollView: HoverPageScrollView! 59 | private var pageScrollView: UIScrollView! 60 | 61 | init(viewControllers: [HoverChildViewController], headerView: UIView, pageTitleView: UIView) { 62 | super.init(nibName: nil, bundle: nil) 63 | self.viewControllers = viewControllers 64 | self.headerView = headerView 65 | self.pageTitleView = pageTitleView 66 | } 67 | 68 | required init?(coder: NSCoder) { 69 | super.init(coder: coder) 70 | } 71 | 72 | public func move(to: Int, animated: Bool) { 73 | view.isUserInteractionEnabled = false 74 | viewControllers.forEach { $0.isCanScroll = true } 75 | pageScrollView.setContentOffset(CGPoint(x: CGFloat(to) * view.frame.width, y: 0), animated: animated) 76 | DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.3) { 77 | self.scrollViewDidEndDecelerating(self.pageScrollView) 78 | self.view.isUserInteractionEnabled = true 79 | } 80 | } 81 | 82 | override func viewDidLoad() { 83 | super.viewDidLoad() 84 | prepareView() 85 | } 86 | 87 | override func viewDidLayoutSubviews() { 88 | super.viewDidLayoutSubviews() 89 | mainScrollView.frame = view.bounds 90 | mainScrollView.contentSize = CGSize(width: 0, height: mainScrollView.frame.height + headerView.frame.height) 91 | pageTitleView.frame.origin.y = headerView.frame.maxY 92 | pageScrollView.frame.origin.y = pageTitleView.frame.maxY 93 | pageScrollView.frame.size = CGSize(width: view.frame.width, height: mainScrollView.contentSize.height - pageTitleView.frame.maxY) 94 | pageScrollView.contentSize = CGSize(width: view.frame.width * CGFloat(viewControllers.count), height: 0) 95 | var scrollViews = Set() 96 | for i in 0.. 0 { 141 | let child = viewControllers[currentIndex]; 142 | child.offsetY = 0 143 | } 144 | } 145 | } 146 | 147 | extension HoverPageViewController: UIScrollViewDelegate { 148 | 149 | func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { 150 | pageScrollView.isScrollEnabled = true 151 | mainScrollView.isScrollEnabled = true 152 | } 153 | 154 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 155 | pageScrollView.isScrollEnabled = true 156 | mainScrollView.isScrollEnabled = true 157 | if scrollView == pageScrollView { 158 | currentIndex = Int(pageScrollView.contentOffset.x / pageScrollView.frame.width + 0.5) % viewControllers.count 159 | delegate?.hoverPageViewController(self, scrollViewDidEndDecelerating: scrollView) 160 | } 161 | } 162 | 163 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 164 | if scrollView == mainScrollView { 165 | pageScrollView.isScrollEnabled = false 166 | let child = viewControllers[currentIndex]; 167 | if child.offsetY > 0 { 168 | scrollView.contentOffset = CGPoint(x: 0, y: headerView.frame.height) 169 | } else { 170 | viewControllers.forEach { $0.offsetY = 0 } 171 | } 172 | } else if scrollView == pageScrollView { 173 | mainScrollView.isScrollEnabled = false 174 | delegate?.hoverPageViewController(self, scrollViewDidScroll: scrollView) 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // HoverDome 4 | // 5 | // Created by admin on 2019/2/27. 6 | // Copyright © 2019 zhouqiao. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | var hoverPageViewController:HoverPageViewController! 14 | let indicator = UIView() 15 | var indicatorMargin:CGFloat = 0 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | view.backgroundColor = UIColor.white 20 | title = "悬停" 21 | prepareView() 22 | } 23 | } 24 | 25 | extension ViewController { 26 | 27 | private func prepareView() { 28 | let headerView = UIScrollView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 200)) 29 | headerView.contentSize = CGSize(width: view.frame.width * 4, height: 0) 30 | headerView.isPagingEnabled = true 31 | 32 | for i in 0..<4{ 33 | let v = UILabel() 34 | v.text = "scrollView" 35 | v.textAlignment = .center 36 | v.backgroundColor = UIColor.random 37 | v.frame = CGRect(origin: CGPoint(x: CGFloat(i) * headerView.frame.width, y: 0), size: headerView.frame.size) 38 | headerView.addSubview(v) 39 | } 40 | 41 | /// 指示器 42 | let pageTitleView = UIView() 43 | pageTitleView.frame.size = CGSize(width: view.frame.width, height: 40) 44 | 45 | /// 添加3个按钮 46 | let buttonSize = CGSize(width: view.frame.width / 3, height: pageTitleView.frame.height) 47 | for i in 0..<3 { 48 | let button = UIButton() 49 | button.tag = i 50 | button.frame.size = buttonSize 51 | button.backgroundColor = UIColor.lightGray 52 | button.frame.origin.x = CGFloat(i) * buttonSize.width 53 | button.setTitleColor(UIColor.black, for: .normal) 54 | button.setTitle("控制器", for: .normal) 55 | button.addTarget(self, action: #selector(ViewController.buttonClick), for: .touchUpInside) 56 | pageTitleView.addSubview(button) 57 | } 58 | 59 | let button = pageTitleView.subviews[0] as! UIButton 60 | button.layoutIfNeeded() 61 | indicator.frame.size = CGSize(width: (button.titleLabel?.frame.width)!, height: 3) 62 | indicator.backgroundColor = UIColor.yellow 63 | indicator.center.x = button.center.x 64 | indicator.frame.origin.y = button.frame.height - indicator.frame.height 65 | indicatorMargin = indicator.frame.origin.x 66 | pageTitleView.addSubview(indicator) 67 | 68 | /// 添加子控制器 69 | var viewControllers = [HoverChildViewController]() 70 | let vc1 = Children1ViewController() 71 | let vc2 = Children2ViewController() 72 | let vc3 = Children3ViewController() 73 | viewControllers.append(vc1) 74 | viewControllers.append(vc2) 75 | viewControllers.append(vc3) 76 | 77 | /// 计算导航栏高度 78 | var barHeight = UIApplication.shared.statusBarFrame.height 79 | if let bar = navigationController?.navigationBar{ 80 | barHeight+=bar.frame.height 81 | } 82 | 83 | /// 添加分页控制器 84 | hoverPageViewController = HoverPageViewController(viewControllers: viewControllers, headerView: headerView, pageTitleView: pageTitleView) 85 | hoverPageViewController.delegate = self 86 | hoverPageViewController.view.frame = CGRect(x: 0, y: barHeight, width: view.frame.width, height: view.frame.height - barHeight) 87 | addChild(hoverPageViewController) 88 | view.addSubview(hoverPageViewController.view) 89 | } 90 | 91 | @objc func buttonClick(btn: UIButton) { 92 | hoverPageViewController.move(to: btn.tag, animated: true) 93 | } 94 | } 95 | 96 | extension ViewController:HoverPageViewControllerDelegate{ 97 | 98 | func hoverPageViewController(_ viewController: HoverPageViewController, scrollViewDidScroll scrollView: UIScrollView) { 99 | let progress = scrollView.contentOffset.x / scrollView.frame.width 100 | indicator.frame.origin.x = ((indicator.frame.width + (indicatorMargin * 2)) * progress) + indicatorMargin 101 | } 102 | 103 | func hoverPageViewController(_ viewController: HoverPageViewController, scrollViewDidEndDecelerating scrollView: UIScrollView) 104 | { 105 | 106 | } 107 | 108 | } 109 | 110 | 111 | extension UIColor { 112 | 113 | static var random: UIColor { 114 | let red = CGFloat(arc4random() % 256) / 255.0 115 | let green = CGFloat(arc4random() % 256) / 255.0 116 | let blue = CGFloat(arc4random() % 256) / 255.0 117 | return UIColor(red: red, green: green, blue: blue, alpha: 1.0) 118 | } 119 | } 120 | 121 | -------------------------------------------------------------------------------- /HoverDome_Swift/HoverDome/hover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QiaokeZ/iOS_HoverPageViewController/07fd92abbccea88edf88bb1884ac09c49ea028f4/HoverDome_Swift/HoverDome/hover.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HoverPageViewController 2 | ### 简书(https://www.jianshu.com/p/ae1b84b107ea) 3 | 4 | 5 | ![image](https://github.com/QiaokeZ/iOS_HoverPageViewController/blob/master/HoverDome_Swift/HoverDome/hover.gif) 6 | 7 | ### 主控制器 8 | ```swift 9 | class ViewController: UIViewController { 10 | 11 | var hoverPageViewController:HoverPageViewController! 12 | let indicator = UIView() 13 | var indicatorMargin:CGFloat = 0 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | view.backgroundColor = UIColor.white 18 | title = "悬停" 19 | prepareView() 20 | } 21 | } 22 | 23 | extension ViewController { 24 | 25 | private func prepareView() { 26 | let headerView = UILabel() 27 | headerView.frame.size = CGSize(width: view.frame.width, height: 200) 28 | headerView.backgroundColor = UIColor.red 29 | headerView.text = "可上下滑动头部" 30 | headerView.textColor = UIColor.white 31 | headerView.textAlignment = .center 32 | 33 | /// 指示器 34 | let pageTitleView = UIView() 35 | pageTitleView.frame.size = CGSize(width: view.frame.width, height: 40) 36 | 37 | /// 添加3个按钮 38 | let buttonSize = CGSize(width: view.frame.width / 3, height: pageTitleView.frame.height) 39 | for i in 0..<3 { 40 | let button = UIButton() 41 | button.tag = i 42 | button.frame.size = buttonSize 43 | button.backgroundColor = UIColor.lightGray 44 | button.frame.origin.x = CGFloat(i) * buttonSize.width 45 | button.setTitleColor(UIColor.black, for: .normal) 46 | button.setTitle("控制器", for: .normal) 47 | button.addTarget(self, action: #selector(ViewController.buttonClick), for: .touchUpInside) 48 | pageTitleView.addSubview(button) 49 | } 50 | 51 | let button = pageTitleView.subviews[0] as! UIButton 52 | button.layoutIfNeeded() 53 | indicator.frame.size = CGSize(width: (button.titleLabel?.frame.width)!, height: 3) 54 | indicator.backgroundColor = UIColor.yellow 55 | indicator.center.x = button.center.x 56 | indicator.frame.origin.y = button.frame.height - indicator.frame.height 57 | indicatorMargin = indicator.frame.origin.x 58 | pageTitleView.addSubview(indicator) 59 | 60 | /// 添加子控制器 61 | var viewControllers = [HoverChildViewController]() 62 | let vc1 = Children1ViewController() 63 | let vc2 = Children2ViewController() 64 | let vc3 = Children3ViewController() 65 | viewControllers.append(vc1) 66 | viewControllers.append(vc2) 67 | viewControllers.append(vc3) 68 | 69 | /// 计算导航栏高度 70 | var barHeight = UIApplication.shared.statusBarFrame.height 71 | if let bar = navigationController?.navigationBar{ 72 | barHeight+=bar.frame.height 73 | } 74 | 75 | /// 添加分页控制器 76 | hoverPageViewController = HoverPageViewController(viewControllers: viewControllers, headerView: headerView, pageTitleView: pageTitleView) 77 | hoverPageViewController.delegate = self 78 | hoverPageViewController.view.frame = CGRect(x: 0, y: barHeight, width: view.frame.width, height: view.frame.height - barHeight) 79 | addChild(hoverPageViewController) 80 | view.addSubview(hoverPageViewController.view) 81 | } 82 | 83 | @objc func buttonClick(btn: UIButton) { 84 | hoverPageViewController.move(to: btn.tag, animated: true) 85 | } 86 | } 87 | 88 | extension ViewController:HoverPageViewControllerDelegate{ 89 | 90 | func hoverPageViewController(_ viewController: HoverPageViewController, scrollViewDidScroll scrollView: UIScrollView) { 91 | let progress = scrollView.contentOffset.x / scrollView.frame.width 92 | indicator.frame.origin.x = ((indicator.frame.width + (indicatorMargin * 2)) * progress) + indicatorMargin 93 | } 94 | } 95 | 96 | ``` 97 | ### 子控制器 98 | ```swift 99 | class Children1ViewController: HoverChildViewController { 100 | 101 | private var tableView:UITableView! 102 | private lazy var items: [String] = { 103 | var items = [String]() 104 | for i in 0..<100 { 105 | items.append("\(i)") 106 | } 107 | return items 108 | }() 109 | 110 | override func viewDidLoad() { 111 | super.viewDidLoad() 112 | view.backgroundColor = UIColor.green 113 | 114 | tableView = UITableView(frame: view.bounds, style: .plain) 115 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "aaaa") 116 | tableView.delegate = self 117 | tableView.dataSource = self 118 | view.addSubview(tableView) 119 | scrollView = tableView 120 | } 121 | 122 | override var offsetY: CGFloat{ 123 | set{ 124 | tableView.contentOffset = CGPoint(x: 0, y: newValue) 125 | } 126 | get{ 127 | return tableView.contentOffset.y 128 | } 129 | } 130 | 131 | override var isCanScroll: Bool{ 132 | didSet{ 133 | if isCanScroll{ 134 | tableView.setContentOffset(CGPoint(x: 0, y: offsetY), animated: false) 135 | } 136 | } 137 | } 138 | } 139 | 140 | extension Children1ViewController: UITableViewDataSource, UITableViewDelegate { 141 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 142 | return items.count 143 | } 144 | 145 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 146 | let cell = tableView.dequeueReusableCell(withIdentifier: "aaaa", for: indexPath) 147 | cell.textLabel?.text = items[indexPath.row] 148 | return cell 149 | } 150 | 151 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 152 | tableView.deselectRow(at: indexPath, animated: true) 153 | } 154 | 155 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 156 | scrollDelegate?.hoverChildViewController(self, scrollViewDidScroll: scrollView) 157 | } 158 | } 159 | ``` 160 | --------------------------------------------------------------------------------