├── NatvieWebView.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── NatvieWebView ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── DetailViewController.h ├── DetailViewController.m ├── Info.plist ├── UIView+HSKit.h ├── UIView+HSKit.m ├── ViewController.h ├── ViewController.m └── main.m └── README.md /NatvieWebView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BA0F4B4F20FEE77B00C2A1B9 /* DetailViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BA0F4B4E20FEE77B00C2A1B9 /* DetailViewController.m */; }; 11 | BAE33B6D20BA81740089ADCC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = BAE33B6C20BA81740089ADCC /* AppDelegate.m */; }; 12 | BAE33B7020BA81740089ADCC /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BAE33B6F20BA81740089ADCC /* ViewController.m */; }; 13 | BAE33B7320BA81740089ADCC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BAE33B7120BA81740089ADCC /* Main.storyboard */; }; 14 | BAE33B7520BA81750089ADCC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BAE33B7420BA81750089ADCC /* Assets.xcassets */; }; 15 | BAE33B7820BA81750089ADCC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BAE33B7620BA81750089ADCC /* LaunchScreen.storyboard */; }; 16 | BAE33B7B20BA81750089ADCC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BAE33B7A20BA81750089ADCC /* main.m */; }; 17 | BAE33B8320BAEE7C0089ADCC /* UIView+HSKit.m in Sources */ = {isa = PBXBuildFile; fileRef = BAE33B8120BAEE7B0089ADCC /* UIView+HSKit.m */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | BA0F4B4D20FEE77A00C2A1B9 /* DetailViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DetailViewController.h; sourceTree = ""; }; 22 | BA0F4B4E20FEE77B00C2A1B9 /* DetailViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DetailViewController.m; sourceTree = ""; }; 23 | BAE33B6820BA81740089ADCC /* NatvieWebView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NatvieWebView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | BAE33B6B20BA81740089ADCC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 25 | BAE33B6C20BA81740089ADCC /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 26 | BAE33B6E20BA81740089ADCC /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 27 | BAE33B6F20BA81740089ADCC /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 28 | BAE33B7220BA81740089ADCC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | BAE33B7420BA81750089ADCC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | BAE33B7720BA81750089ADCC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | BAE33B7920BA81750089ADCC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | BAE33B7A20BA81750089ADCC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | BAE33B8120BAEE7B0089ADCC /* UIView+HSKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+HSKit.m"; sourceTree = ""; }; 34 | BAE33B8220BAEE7B0089ADCC /* UIView+HSKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+HSKit.h"; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | BAE33B6520BA81740089ADCC /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | ); 43 | runOnlyForDeploymentPostprocessing = 0; 44 | }; 45 | /* End PBXFrameworksBuildPhase section */ 46 | 47 | /* Begin PBXGroup section */ 48 | BAE33B5F20BA81740089ADCC = { 49 | isa = PBXGroup; 50 | children = ( 51 | BAE33B6A20BA81740089ADCC /* NatvieWebView */, 52 | BAE33B6920BA81740089ADCC /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | BAE33B6920BA81740089ADCC /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | BAE33B6820BA81740089ADCC /* NatvieWebView.app */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | BAE33B6A20BA81740089ADCC /* NatvieWebView */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | BAE33B6B20BA81740089ADCC /* AppDelegate.h */, 68 | BAE33B6C20BA81740089ADCC /* AppDelegate.m */, 69 | BAE33B6E20BA81740089ADCC /* ViewController.h */, 70 | BAE33B6F20BA81740089ADCC /* ViewController.m */, 71 | BA0F4B4D20FEE77A00C2A1B9 /* DetailViewController.h */, 72 | BA0F4B4E20FEE77B00C2A1B9 /* DetailViewController.m */, 73 | BAE33B8220BAEE7B0089ADCC /* UIView+HSKit.h */, 74 | BAE33B8120BAEE7B0089ADCC /* UIView+HSKit.m */, 75 | BAE33B7120BA81740089ADCC /* Main.storyboard */, 76 | BAE33B7420BA81750089ADCC /* Assets.xcassets */, 77 | BAE33B7620BA81750089ADCC /* LaunchScreen.storyboard */, 78 | BAE33B7920BA81750089ADCC /* Info.plist */, 79 | BAE33B7A20BA81750089ADCC /* main.m */, 80 | ); 81 | path = NatvieWebView; 82 | sourceTree = ""; 83 | }; 84 | /* End PBXGroup section */ 85 | 86 | /* Begin PBXNativeTarget section */ 87 | BAE33B6720BA81740089ADCC /* NatvieWebView */ = { 88 | isa = PBXNativeTarget; 89 | buildConfigurationList = BAE33B7E20BA81750089ADCC /* Build configuration list for PBXNativeTarget "NatvieWebView" */; 90 | buildPhases = ( 91 | BAE33B6420BA81740089ADCC /* Sources */, 92 | BAE33B6520BA81740089ADCC /* Frameworks */, 93 | BAE33B6620BA81740089ADCC /* Resources */, 94 | ); 95 | buildRules = ( 96 | ); 97 | dependencies = ( 98 | ); 99 | name = NatvieWebView; 100 | productName = NatvieWebView; 101 | productReference = BAE33B6820BA81740089ADCC /* NatvieWebView.app */; 102 | productType = "com.apple.product-type.application"; 103 | }; 104 | /* End PBXNativeTarget section */ 105 | 106 | /* Begin PBXProject section */ 107 | BAE33B6020BA81740089ADCC /* Project object */ = { 108 | isa = PBXProject; 109 | attributes = { 110 | LastUpgradeCheck = 0930; 111 | ORGANIZATIONNAME = ThinkCode; 112 | TargetAttributes = { 113 | BAE33B6720BA81740089ADCC = { 114 | CreatedOnToolsVersion = 9.3; 115 | }; 116 | }; 117 | }; 118 | buildConfigurationList = BAE33B6320BA81740089ADCC /* Build configuration list for PBXProject "NatvieWebView" */; 119 | compatibilityVersion = "Xcode 9.3"; 120 | developmentRegion = en; 121 | hasScannedForEncodings = 0; 122 | knownRegions = ( 123 | en, 124 | Base, 125 | ); 126 | mainGroup = BAE33B5F20BA81740089ADCC; 127 | productRefGroup = BAE33B6920BA81740089ADCC /* Products */; 128 | projectDirPath = ""; 129 | projectRoot = ""; 130 | targets = ( 131 | BAE33B6720BA81740089ADCC /* NatvieWebView */, 132 | ); 133 | }; 134 | /* End PBXProject section */ 135 | 136 | /* Begin PBXResourcesBuildPhase section */ 137 | BAE33B6620BA81740089ADCC /* Resources */ = { 138 | isa = PBXResourcesBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | BAE33B7820BA81750089ADCC /* LaunchScreen.storyboard in Resources */, 142 | BAE33B7520BA81750089ADCC /* Assets.xcassets in Resources */, 143 | BAE33B7320BA81740089ADCC /* Main.storyboard in Resources */, 144 | ); 145 | runOnlyForDeploymentPostprocessing = 0; 146 | }; 147 | /* End PBXResourcesBuildPhase section */ 148 | 149 | /* Begin PBXSourcesBuildPhase section */ 150 | BAE33B6420BA81740089ADCC /* Sources */ = { 151 | isa = PBXSourcesBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | BA0F4B4F20FEE77B00C2A1B9 /* DetailViewController.m in Sources */, 155 | BAE33B8320BAEE7C0089ADCC /* UIView+HSKit.m in Sources */, 156 | BAE33B7020BA81740089ADCC /* ViewController.m in Sources */, 157 | BAE33B7B20BA81750089ADCC /* main.m in Sources */, 158 | BAE33B6D20BA81740089ADCC /* AppDelegate.m in Sources */, 159 | ); 160 | runOnlyForDeploymentPostprocessing = 0; 161 | }; 162 | /* End PBXSourcesBuildPhase section */ 163 | 164 | /* Begin PBXVariantGroup section */ 165 | BAE33B7120BA81740089ADCC /* Main.storyboard */ = { 166 | isa = PBXVariantGroup; 167 | children = ( 168 | BAE33B7220BA81740089ADCC /* Base */, 169 | ); 170 | name = Main.storyboard; 171 | sourceTree = ""; 172 | }; 173 | BAE33B7620BA81750089ADCC /* LaunchScreen.storyboard */ = { 174 | isa = PBXVariantGroup; 175 | children = ( 176 | BAE33B7720BA81750089ADCC /* Base */, 177 | ); 178 | name = LaunchScreen.storyboard; 179 | sourceTree = ""; 180 | }; 181 | /* End PBXVariantGroup section */ 182 | 183 | /* Begin XCBuildConfiguration section */ 184 | BAE33B7C20BA81750089ADCC /* Debug */ = { 185 | isa = XCBuildConfiguration; 186 | buildSettings = { 187 | ALWAYS_SEARCH_USER_PATHS = NO; 188 | CLANG_ANALYZER_NONNULL = YES; 189 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 191 | CLANG_CXX_LIBRARY = "libc++"; 192 | CLANG_ENABLE_MODULES = YES; 193 | CLANG_ENABLE_OBJC_ARC = YES; 194 | CLANG_ENABLE_OBJC_WEAK = YES; 195 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 196 | CLANG_WARN_BOOL_CONVERSION = YES; 197 | CLANG_WARN_COMMA = YES; 198 | CLANG_WARN_CONSTANT_CONVERSION = YES; 199 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 200 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 201 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 202 | CLANG_WARN_EMPTY_BODY = YES; 203 | CLANG_WARN_ENUM_CONVERSION = YES; 204 | CLANG_WARN_INFINITE_RECURSION = YES; 205 | CLANG_WARN_INT_CONVERSION = YES; 206 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 207 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 208 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 209 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 210 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 211 | CLANG_WARN_STRICT_PROTOTYPES = YES; 212 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 213 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 214 | CLANG_WARN_UNREACHABLE_CODE = YES; 215 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 216 | CODE_SIGN_IDENTITY = "iPhone Developer"; 217 | COPY_PHASE_STRIP = NO; 218 | DEBUG_INFORMATION_FORMAT = dwarf; 219 | ENABLE_STRICT_OBJC_MSGSEND = YES; 220 | ENABLE_TESTABILITY = YES; 221 | GCC_C_LANGUAGE_STANDARD = gnu11; 222 | GCC_DYNAMIC_NO_PIC = NO; 223 | GCC_NO_COMMON_BLOCKS = YES; 224 | GCC_OPTIMIZATION_LEVEL = 0; 225 | GCC_PREPROCESSOR_DEFINITIONS = ( 226 | "DEBUG=1", 227 | "$(inherited)", 228 | ); 229 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 230 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 231 | GCC_WARN_UNDECLARED_SELECTOR = YES; 232 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 233 | GCC_WARN_UNUSED_FUNCTION = YES; 234 | GCC_WARN_UNUSED_VARIABLE = YES; 235 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 236 | MTL_ENABLE_DEBUG_INFO = YES; 237 | ONLY_ACTIVE_ARCH = YES; 238 | SDKROOT = iphoneos; 239 | }; 240 | name = Debug; 241 | }; 242 | BAE33B7D20BA81750089ADCC /* Release */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | ALWAYS_SEARCH_USER_PATHS = NO; 246 | CLANG_ANALYZER_NONNULL = YES; 247 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 248 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 249 | CLANG_CXX_LIBRARY = "libc++"; 250 | CLANG_ENABLE_MODULES = YES; 251 | CLANG_ENABLE_OBJC_ARC = YES; 252 | CLANG_ENABLE_OBJC_WEAK = YES; 253 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 254 | CLANG_WARN_BOOL_CONVERSION = YES; 255 | CLANG_WARN_COMMA = YES; 256 | CLANG_WARN_CONSTANT_CONVERSION = YES; 257 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 258 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 259 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 260 | CLANG_WARN_EMPTY_BODY = YES; 261 | CLANG_WARN_ENUM_CONVERSION = YES; 262 | CLANG_WARN_INFINITE_RECURSION = YES; 263 | CLANG_WARN_INT_CONVERSION = YES; 264 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 265 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 266 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 269 | CLANG_WARN_STRICT_PROTOTYPES = YES; 270 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 271 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 272 | CLANG_WARN_UNREACHABLE_CODE = YES; 273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 274 | CODE_SIGN_IDENTITY = "iPhone Developer"; 275 | COPY_PHASE_STRIP = NO; 276 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 277 | ENABLE_NS_ASSERTIONS = NO; 278 | ENABLE_STRICT_OBJC_MSGSEND = YES; 279 | GCC_C_LANGUAGE_STANDARD = gnu11; 280 | GCC_NO_COMMON_BLOCKS = YES; 281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 283 | GCC_WARN_UNDECLARED_SELECTOR = YES; 284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 285 | GCC_WARN_UNUSED_FUNCTION = YES; 286 | GCC_WARN_UNUSED_VARIABLE = YES; 287 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 288 | MTL_ENABLE_DEBUG_INFO = NO; 289 | SDKROOT = iphoneos; 290 | VALIDATE_PRODUCT = YES; 291 | }; 292 | name = Release; 293 | }; 294 | BAE33B7F20BA81750089ADCC /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 298 | CODE_SIGN_STYLE = Automatic; 299 | DEVELOPMENT_TEAM = ED529Z92CK; 300 | INFOPLIST_FILE = NatvieWebView/Info.plist; 301 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 302 | LD_RUNPATH_SEARCH_PATHS = ( 303 | "$(inherited)", 304 | "@executable_path/Frameworks", 305 | ); 306 | PRODUCT_BUNDLE_IDENTIFIER = cn.thinkcode.NatvieWebView; 307 | PRODUCT_NAME = "$(TARGET_NAME)"; 308 | TARGETED_DEVICE_FAMILY = "1,2"; 309 | }; 310 | name = Debug; 311 | }; 312 | BAE33B8020BA81750089ADCC /* Release */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 316 | CODE_SIGN_STYLE = Automatic; 317 | DEVELOPMENT_TEAM = ED529Z92CK; 318 | INFOPLIST_FILE = NatvieWebView/Info.plist; 319 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 320 | LD_RUNPATH_SEARCH_PATHS = ( 321 | "$(inherited)", 322 | "@executable_path/Frameworks", 323 | ); 324 | PRODUCT_BUNDLE_IDENTIFIER = cn.thinkcode.NatvieWebView; 325 | PRODUCT_NAME = "$(TARGET_NAME)"; 326 | TARGETED_DEVICE_FAMILY = "1,2"; 327 | }; 328 | name = Release; 329 | }; 330 | /* End XCBuildConfiguration section */ 331 | 332 | /* Begin XCConfigurationList section */ 333 | BAE33B6320BA81740089ADCC /* Build configuration list for PBXProject "NatvieWebView" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | BAE33B7C20BA81750089ADCC /* Debug */, 337 | BAE33B7D20BA81750089ADCC /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | BAE33B7E20BA81750089ADCC /* Build configuration list for PBXNativeTarget "NatvieWebView" */ = { 343 | isa = XCConfigurationList; 344 | buildConfigurations = ( 345 | BAE33B7F20BA81750089ADCC /* Debug */, 346 | BAE33B8020BA81750089ADCC /* Release */, 347 | ); 348 | defaultConfigurationIsVisible = 0; 349 | defaultConfigurationName = Release; 350 | }; 351 | /* End XCConfigurationList section */ 352 | }; 353 | rootObject = BAE33B6020BA81740089ADCC /* Project object */; 354 | } 355 | -------------------------------------------------------------------------------- /NatvieWebView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /NatvieWebView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/5/27. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /NatvieWebView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/5/27. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // 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. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // 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. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // 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. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /NatvieWebView/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 | } -------------------------------------------------------------------------------- /NatvieWebView/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /NatvieWebView/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /NatvieWebView/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 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /NatvieWebView/DetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.h 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/7/18. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DetailViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /NatvieWebView/DetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DetailViewController.m 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/7/18. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import "DetailViewController.h" 10 | #import 11 | #import "UIView+HSKit.h" 12 | 13 | /** 14 | * 最上面有个View,WebView和TableView 15 | */ 16 | @interface DetailViewController () 18 | 19 | @property (nonatomic, strong) WKWebView *webView; 20 | 21 | @property (nonatomic, strong) UITableView *tableView; 22 | 23 | @property (nonatomic, strong) UIScrollView *containerScrollView; 24 | 25 | @property (nonatomic, strong) UIView *contentView; 26 | 27 | @property (nonatomic, strong) UIView *topView; 28 | 29 | @end 30 | 31 | @implementation DetailViewController{ 32 | CGFloat _lastWebViewContentHeight; 33 | CGFloat _lastTableViewContentHeight; 34 | } 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | [self initValue]; 39 | [self initView]; 40 | [self addObservers]; 41 | 42 | NSString *path = @"https://www.jianshu.com/p/f31e39d3ce41"; 43 | NSString *path2 = @"http://127.0.0.1/openItunes.html"; 44 | 45 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:path]]; 46 | request.cachePolicy = NSURLRequestReloadIgnoringCacheData; 47 | [self.webView loadRequest:request]; 48 | } 49 | 50 | - (void)dealloc{ 51 | [self removeObservers]; 52 | } 53 | 54 | - (void)didReceiveMemoryWarning { 55 | [super didReceiveMemoryWarning]; 56 | } 57 | 58 | - (void)initValue{ 59 | _lastWebViewContentHeight = 0; 60 | _lastTableViewContentHeight = 0; 61 | } 62 | 63 | - (void)initView{ 64 | 65 | [self.contentView addSubview:self.topView]; 66 | [self.contentView addSubview:self.webView]; 67 | [self.contentView addSubview:self.tableView]; 68 | 69 | [self.view addSubview:self.containerScrollView]; 70 | [self.containerScrollView addSubview:self.contentView]; 71 | 72 | self.contentView.frame = CGRectMake(0, 0, self.view.width, self.view.height * 2); 73 | self.topView.frame = CGRectMake(0, 0, self.view.width, 200); 74 | 75 | self.webView.top = self.topView.height; 76 | self.webView.height = self.view.height; 77 | self.tableView.top = self.webView.bottom; 78 | } 79 | 80 | 81 | #pragma mark - Observers 82 | - (void)addObservers{ 83 | [self.webView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew context:nil]; 84 | [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil]; 85 | } 86 | 87 | - (void)removeObservers{ 88 | [self.webView removeObserver:self forKeyPath:@"scrollView.contentSize"]; 89 | [self.tableView removeObserver:self forKeyPath:@"contentSize"]; 90 | } 91 | 92 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 93 | if (object == _webView) { 94 | if ([keyPath isEqualToString:@"scrollView.contentSize"]) { 95 | [self updateContainerScrollViewContentSize:0 webViewContentHeight:0]; 96 | } 97 | }else if(object == _tableView) { 98 | if ([keyPath isEqualToString:@"contentSize"]) { 99 | [self updateContainerScrollViewContentSize:0 webViewContentHeight:0]; 100 | } 101 | } 102 | } 103 | 104 | - (void)updateContainerScrollViewContentSize:(NSInteger)flag webViewContentHeight:(CGFloat)inWebViewContentHeight{ 105 | 106 | CGFloat webViewContentHeight = flag==1 ?inWebViewContentHeight :self.webView.scrollView.contentSize.height; 107 | CGFloat tableViewContentHeight = self.tableView.contentSize.height; 108 | 109 | if (webViewContentHeight == _lastWebViewContentHeight && tableViewContentHeight == _lastTableViewContentHeight) { 110 | return; 111 | } 112 | 113 | _lastWebViewContentHeight = webViewContentHeight; 114 | _lastTableViewContentHeight = tableViewContentHeight; 115 | 116 | self.containerScrollView.contentSize = CGSizeMake(self.view.width, self.webView.top + webViewContentHeight + tableViewContentHeight); 117 | 118 | CGFloat webViewHeight = (webViewContentHeight < self.view.height) ?webViewContentHeight :self.view.height ; 119 | CGFloat tableViewHeight = tableViewContentHeight < self.view.height ?tableViewContentHeight :self.view.height; 120 | self.webView.height = webViewHeight <= 0.1 ?0.1 :webViewHeight; 121 | self.contentView.height = self.webView.top +webViewHeight + tableViewHeight; 122 | self.tableView.height = tableViewHeight; 123 | self.tableView.top = self.webView.bottom; 124 | 125 | //Fix:contentSize变化时需要更新各个控件的位置 126 | [self scrollViewDidScroll:self.containerScrollView]; 127 | } 128 | 129 | #pragma mark - UIScrollViewDelegate 130 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 131 | if (_containerScrollView != scrollView) { 132 | return; 133 | } 134 | 135 | CGFloat offsetY = scrollView.contentOffset.y; 136 | 137 | CGFloat webViewHeight = self.webView.height; 138 | CGFloat tableViewHeight = self.tableView.height; 139 | 140 | CGFloat webViewContentHeight = self.webView.scrollView.contentSize.height; 141 | CGFloat tableViewContentHeight = self.tableView.contentSize.height; 142 | //CGFloat topViewHeight = self.topView.height; 143 | CGFloat webViewTop = self.webView.top; 144 | 145 | CGFloat netOffsetY = offsetY - webViewTop; 146 | 147 | if (netOffsetY <= 0) { 148 | self.contentView.top = 0; 149 | self.webView.scrollView.contentOffset = CGPointZero; 150 | self.tableView.contentOffset = CGPointZero; 151 | }else if(netOffsetY < webViewContentHeight - webViewHeight){ 152 | self.contentView.top = netOffsetY; 153 | self.webView.scrollView.contentOffset = CGPointMake(0, netOffsetY); 154 | self.tableView.contentOffset = CGPointZero; 155 | }else if(netOffsetY < webViewContentHeight){ 156 | self.contentView.top = webViewContentHeight - webViewHeight; 157 | self.webView.scrollView.contentOffset = CGPointMake(0, webViewContentHeight - webViewHeight); 158 | self.tableView.contentOffset = CGPointZero; 159 | }else if(netOffsetY < webViewContentHeight + tableViewContentHeight - tableViewHeight){ 160 | self.contentView.top = offsetY - webViewHeight - webViewTop; 161 | self.tableView.contentOffset = CGPointMake(0, offsetY - webViewContentHeight - webViewTop); 162 | self.webView.scrollView.contentOffset = CGPointMake(0, webViewContentHeight - webViewHeight); 163 | }else if(netOffsetY <= webViewContentHeight + tableViewContentHeight ){ 164 | self.contentView.top = self.containerScrollView.contentSize.height - self.contentView.height; 165 | self.webView.scrollView.contentOffset = CGPointMake(0, webViewContentHeight - webViewHeight); 166 | self.tableView.contentOffset = CGPointMake(0, tableViewContentHeight - tableViewHeight); 167 | }else { 168 | //do nothing 169 | NSLog(@"do nothing"); 170 | } 171 | } 172 | 173 | #pragma mark - UITableViewDataSouce 174 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 175 | return 1; 176 | } 177 | 178 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 179 | return 200; 180 | } 181 | 182 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 183 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 184 | if (cell == nil) { 185 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; 186 | cell.backgroundColor = [UIColor redColor]; 187 | } 188 | 189 | cell.textLabel.text = @(indexPath.row).stringValue; 190 | return cell; 191 | } 192 | 193 | #pragma mark - private 194 | - (WKWebView *)webView{ 195 | if (_webView == nil) { 196 | WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; 197 | _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration]; 198 | _webView.scrollView.scrollEnabled = NO; 199 | _webView.navigationDelegate = self; 200 | } 201 | 202 | return _webView; 203 | } 204 | 205 | - (UITableView *)tableView{ 206 | if (_tableView == nil) { 207 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 208 | _tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); 209 | _tableView.delegate = self; 210 | _tableView.dataSource = self; 211 | _tableView.tableFooterView = [UIView new]; 212 | _tableView.scrollEnabled = NO; 213 | 214 | } 215 | return _tableView; 216 | } 217 | 218 | - (UIScrollView *)containerScrollView{ 219 | if (_containerScrollView == nil) { 220 | _containerScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; 221 | _containerScrollView.delegate = self; 222 | _containerScrollView.alwaysBounceVertical = YES; 223 | } 224 | 225 | return _containerScrollView; 226 | } 227 | 228 | - (UIView *)contentView{ 229 | if (_contentView == nil) { 230 | _contentView = [[UIView alloc] init]; 231 | } 232 | 233 | return _contentView; 234 | } 235 | 236 | - (UIView *)topView{ 237 | if (_topView == nil) { 238 | _topView = [[UIView alloc] init]; 239 | _topView.backgroundColor = [UIColor yellowColor]; 240 | } 241 | 242 | return _topView; 243 | } 244 | 245 | 246 | @end 247 | -------------------------------------------------------------------------------- /NatvieWebView/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 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | Main 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | 40 | UISupportedInterfaceOrientations~ipad 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationPortraitUpsideDown 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /NatvieWebView/UIView+HSKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+HSKit.h 3 | // HSKit 4 | // 5 | // Created by hejianyuan on 16/9/18. 6 | // Copyright © 2016年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (HSKit) 12 | 13 | /*UIView Frame*/ 14 | @property (nonatomic, assign) CGFloat left; 15 | @property (nonatomic, assign) CGFloat right; 16 | @property (nonatomic, assign) CGFloat top; 17 | @property (nonatomic, assign) CGFloat bottom; 18 | 19 | @property (nonatomic, assign) CGFloat width; 20 | @property (nonatomic, assign) CGFloat height; 21 | 22 | @property (nonatomic, assign) CGFloat centerX; 23 | @property (nonatomic, assign) CGFloat centerY; 24 | 25 | @property (nonatomic, assign, readonly) CGPoint boundsCenter; 26 | @property (nonatomic, assign, readonly) CGFloat boundsCenterX; 27 | @property (nonatomic, assign, readonly) CGFloat boundsCenterY; 28 | 29 | @property (nonatomic, assign) CGPoint origin; 30 | @property (nonatomic, assign) CGSize size; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /NatvieWebView/UIView+HSKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+HSKit.m 3 | // HSKit 4 | // 5 | // Created by hejianyuan on 16/9/18. 6 | // Copyright © 2016年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import "UIView+HSKit.h" 10 | 11 | @implementation UIView (HSKit) 12 | 13 | #pragma mark - Frame 14 | 15 | - (CGFloat)left{ 16 | return self.frame.origin.x; 17 | } 18 | 19 | - (void)setLeft:(CGFloat)left{ 20 | CGRect frame = self.frame; 21 | frame.origin.x = left; 22 | self.frame = frame; 23 | } 24 | 25 | - (CGFloat)right{ 26 | return CGRectGetMaxX(self.frame); 27 | } 28 | 29 | -(void)setRight:(CGFloat)right{ 30 | CGRect frame = self.frame; 31 | frame.origin.x = right - frame.size.width; 32 | self.frame = frame; 33 | } 34 | 35 | - (CGFloat)top{ 36 | return self.frame.origin.y; 37 | } 38 | 39 | - (void)setTop:(CGFloat)top{ 40 | CGRect frame = self.frame; 41 | frame.origin.y = top; 42 | self.frame = frame; 43 | } 44 | 45 | - (CGFloat)bottom{ 46 | return CGRectGetMaxY(self.frame); 47 | } 48 | 49 | - (void)setBottom:(CGFloat)bottom{ 50 | CGRect frame = self.frame; 51 | frame.origin.y = bottom - frame.size.height; 52 | self.frame = frame; 53 | } 54 | 55 | - (CGFloat)width{ 56 | return self.frame.size.width; 57 | } 58 | 59 | - (void)setWidth:(CGFloat)width{ 60 | CGRect frame = self.frame; 61 | frame.size.width = width; 62 | self.frame = frame; 63 | } 64 | 65 | - (CGFloat)height{ 66 | return self.frame.size.height; 67 | } 68 | 69 | - (void)setHeight:(CGFloat)height{ 70 | CGRect frame = self.frame; 71 | frame.size.height = height; 72 | self.frame = frame; 73 | } 74 | 75 | - (CGFloat)centerX{ 76 | return self.center.x; 77 | } 78 | 79 | - (void)setCenterX:(CGFloat)centerX{ 80 | CGPoint pt = self.center; 81 | pt.x = centerX; 82 | self.center = pt; 83 | } 84 | 85 | - (CGFloat)centerY{ 86 | return self.center.y; 87 | } 88 | 89 | - (void)setCenterY:(CGFloat)centerY{ 90 | CGPoint pt = self.center; 91 | pt.y = centerY; 92 | self.center = pt; 93 | } 94 | 95 | - (CGPoint)boundsCenter{ 96 | return CGPointMake(self.width / 2.f, self.height / 2.f); 97 | } 98 | 99 | - (CGFloat)boundsCenterX{ 100 | return self.width / 2.f; 101 | } 102 | 103 | - (CGFloat)boundsCenterY{ 104 | return self.height / 2.f; 105 | } 106 | 107 | - (CGPoint)origin{ 108 | return self.frame.origin; 109 | } 110 | 111 | - (void)setOrigin:(CGPoint)origin{ 112 | CGRect frame = self.frame; 113 | frame.origin = origin; 114 | self.frame = frame; 115 | } 116 | 117 | - (CGSize)size{ 118 | return self.frame.size; 119 | } 120 | 121 | - (void)setSize:(CGSize)size{ 122 | CGRect frame = self.frame; 123 | frame.size = size; 124 | self.frame = frame; 125 | } 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /NatvieWebView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/5/27. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /NatvieWebView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/5/27. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import 11 | #import "UIView+HSKit.h" 12 | 13 | /** 14 | * 只有WebView和TableView 15 | */ 16 | @interface ViewController () 18 | 19 | @property (nonatomic, strong) WKWebView *webView; 20 | 21 | @property (nonatomic, strong) UITableView *tableView; 22 | 23 | @property (nonatomic, strong) UIScrollView *containerScrollView; 24 | 25 | @property (nonatomic, strong) UIView *contentView; 26 | 27 | @end 28 | 29 | @implementation ViewController{ 30 | CGFloat _lastWebViewContentHeight; 31 | CGFloat _lastTableViewContentHeight; 32 | } 33 | 34 | - (void)viewDidLoad { 35 | [super viewDidLoad]; 36 | [self initValue]; 37 | [self initView]; 38 | [self addObservers]; 39 | 40 | NSString *path = @"https://www.jianshu.com/p/f31e39d3ce41"; 41 | NSString *path2 = @"http://127.0.0.1/openItunes.html"; 42 | 43 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:path]]; 44 | request.cachePolicy = NSURLRequestReloadIgnoringCacheData; 45 | [self.webView loadRequest:request]; 46 | } 47 | 48 | - (void)dealloc{ 49 | [self removeObservers]; 50 | } 51 | 52 | - (void)didReceiveMemoryWarning { 53 | [super didReceiveMemoryWarning]; 54 | } 55 | 56 | - (void)initValue{ 57 | _lastWebViewContentHeight = 0; 58 | _lastTableViewContentHeight = 0; 59 | } 60 | 61 | - (void)initView{ 62 | [self.contentView addSubview:self.webView]; 63 | [self.contentView addSubview:self.tableView]; 64 | 65 | [self.view addSubview:self.containerScrollView]; 66 | [self.containerScrollView addSubview:self.contentView]; 67 | 68 | self.contentView.frame = CGRectMake(0, 0, self.view.width, self.view.height * 2); 69 | self.webView.top = 0; 70 | self.webView.height = self.view.height; 71 | self.tableView.top = self.webView.bottom; 72 | } 73 | 74 | 75 | #pragma mark - Observers 76 | - (void)addObservers{ 77 | [self.webView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew context:nil]; 78 | [self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil]; 79 | } 80 | 81 | - (void)removeObservers{ 82 | [self.webView removeObserver:self forKeyPath:@"scrollView.contentSize"]; 83 | [self.tableView removeObserver:self forKeyPath:@"contentSize"]; 84 | } 85 | 86 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 87 | if (object == _webView) { 88 | if ([keyPath isEqualToString:@"scrollView.contentSize"]) { 89 | [self updateContainerScrollViewContentSize:0 webViewContentHeight:0]; 90 | } 91 | }else if(object == _tableView) { 92 | if ([keyPath isEqualToString:@"contentSize"]) { 93 | [self updateContainerScrollViewContentSize:0 webViewContentHeight:0]; 94 | } 95 | } 96 | } 97 | 98 | - (void)updateContainerScrollViewContentSize:(NSInteger)flag webViewContentHeight:(CGFloat)inWebViewContentHeight{ 99 | 100 | CGFloat webViewContentHeight = flag==1 ?inWebViewContentHeight :self.webView.scrollView.contentSize.height; 101 | CGFloat tableViewContentHeight = self.tableView.contentSize.height; 102 | 103 | if (webViewContentHeight == _lastWebViewContentHeight && tableViewContentHeight == _lastTableViewContentHeight) { 104 | return; 105 | } 106 | 107 | _lastWebViewContentHeight = webViewContentHeight; 108 | _lastTableViewContentHeight = tableViewContentHeight; 109 | 110 | self.containerScrollView.contentSize = CGSizeMake(self.view.width, webViewContentHeight + tableViewContentHeight); 111 | 112 | CGFloat webViewHeight = (webViewContentHeight < self.view.height) ?webViewContentHeight :self.view.height ; 113 | CGFloat tableViewHeight = tableViewContentHeight < self.view.height ?tableViewContentHeight :self.view.height; 114 | self.webView.height = webViewHeight <= 0.1 ?0.1 :webViewHeight; 115 | self.contentView.height = webViewHeight + tableViewHeight; 116 | self.tableView.height = tableViewHeight; 117 | self.tableView.top = self.webView.bottom; 118 | 119 | //Fix:contentSize变化时需要更新各个控件的位置 120 | [self scrollViewDidScroll:self.containerScrollView]; 121 | } 122 | 123 | #pragma mark - UIScrollViewDelegate 124 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ 125 | if (_containerScrollView != scrollView) { 126 | return; 127 | } 128 | 129 | CGFloat offsetY = scrollView.contentOffset.y; 130 | 131 | CGFloat webViewHeight = self.webView.height; 132 | CGFloat tableViewHeight = self.tableView.height; 133 | 134 | CGFloat webViewContentHeight = self.webView.scrollView.contentSize.height; 135 | CGFloat tableViewContentHeight = self.tableView.contentSize.height; 136 | 137 | if (offsetY <= 0) { 138 | self.contentView.top = 0; 139 | self.webView.scrollView.contentOffset = CGPointZero; 140 | self.tableView.contentOffset = CGPointZero; 141 | }else if(offsetY < webViewContentHeight - webViewHeight){ 142 | self.contentView.top = offsetY; 143 | self.webView.scrollView.contentOffset = CGPointMake(0, offsetY); 144 | self.tableView.contentOffset = CGPointZero; 145 | }else if(offsetY < webViewContentHeight){ 146 | self.contentView.top = webViewContentHeight - webViewHeight; 147 | self.webView.scrollView.contentOffset = CGPointMake(0, webViewContentHeight - webViewHeight); 148 | self.tableView.contentOffset = CGPointZero; 149 | }else if(offsetY < webViewContentHeight + tableViewContentHeight - tableViewHeight){ 150 | self.contentView.top = offsetY - webViewHeight; 151 | self.tableView.contentOffset = CGPointMake(0, offsetY - webViewContentHeight); 152 | self.webView.scrollView.contentOffset = CGPointMake(0, webViewContentHeight - webViewHeight); 153 | }else if(offsetY <= webViewContentHeight + tableViewContentHeight ){ 154 | self.contentView.top = self.containerScrollView.contentSize.height - self.contentView.height; 155 | self.webView.scrollView.contentOffset = CGPointMake(0, webViewContentHeight - webViewHeight); 156 | self.tableView.contentOffset = CGPointMake(0, tableViewContentHeight - tableViewHeight); 157 | }else { 158 | //do nothing 159 | NSLog(@"do nothing"); 160 | } 161 | } 162 | 163 | #pragma mark - UITableViewDataSouce 164 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 165 | return 1; 166 | } 167 | 168 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 169 | return 200; 170 | } 171 | 172 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 173 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 174 | if (cell == nil) { 175 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; 176 | cell.backgroundColor = [UIColor redColor]; 177 | } 178 | 179 | cell.textLabel.text = @(indexPath.row).stringValue; 180 | return cell; 181 | } 182 | 183 | #pragma mark - private 184 | - (WKWebView *)webView{ 185 | if (_webView == nil) { 186 | WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init]; 187 | _webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:configuration]; 188 | _webView.scrollView.scrollEnabled = NO; 189 | _webView.navigationDelegate = self; 190 | } 191 | 192 | return _webView; 193 | } 194 | 195 | - (UITableView *)tableView{ 196 | if (_tableView == nil) { 197 | _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; 198 | _tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); 199 | _tableView.delegate = self; 200 | _tableView.dataSource = self; 201 | _tableView.tableFooterView = [UIView new]; 202 | _tableView.scrollEnabled = NO; 203 | 204 | } 205 | return _tableView; 206 | } 207 | 208 | - (UIScrollView *)containerScrollView{ 209 | if (_containerScrollView == nil) { 210 | _containerScrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds]; 211 | _containerScrollView.delegate = self; 212 | _containerScrollView.alwaysBounceVertical = YES; 213 | } 214 | 215 | return _containerScrollView; 216 | } 217 | 218 | - (UIView *)contentView{ 219 | if (_contentView == nil) { 220 | _contentView = [[UIView alloc] init]; 221 | } 222 | 223 | return _contentView; 224 | } 225 | 226 | @end 227 | -------------------------------------------------------------------------------- /NatvieWebView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // NatvieWebView 4 | // 5 | // Created by hejianyuan on 2018/5/27. 6 | // Copyright © 2018年 ThinkCode. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HSNatvieWebView 2 | iOS资讯详情页实现—WebView和TableView混合使用 3 | --------------------------------------------------------------------------------