LMWebviewController.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. //
  2. // LMWebviewController.m
  3. // LMWebview
  4. //
  5. // Created by Leesim on 2018/6/25.
  6. // Copyright © 2018年 LiMing. All rights reserved.
  7. //
  8. #import "LMWebviewController.h"
  9. #import <WebKit/WebKit.h>
  10. #define NAV_HEIGHT (([[UIApplication sharedApplication] statusBarFrame].size.height)+44.0f)
  11. #define LMRGBAColor(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:a]
  12. @interface LMWebviewController ()<WKNavigationDelegate,WKUIDelegate,UIGestureRecognizerDelegate>
  13. @property (nonatomic,strong) WKWebView * webview;
  14. @property (nonatomic,strong) UIBarButtonItem * customBackBarItem;
  15. @property (nonatomic,strong) UIBarButtonItem * closeButtonItem;
  16. @property (nonatomic,strong) UIBarButtonItem* refreshBarItem;
  17. @property (nonatomic,strong) UIView * progressGetView;
  18. @property (nonatomic,strong) UIView * errorShowView;
  19. //为了修复侧滑手势在webview上响应
  20. @property (nonatomic,assign) id delegate;
  21. //注入方法名 用于接受JS调用原生方法 让Web端掉用iOS端代码
  22. @property (nonatomic,strong) WKWebViewConfiguration *webConfig;
  23. @end
  24. @implementation LMWebviewController
  25. //由于,手动设置了导航栏左按钮,因此我们会发现系统自带的侧滑返回功能失效了,为了网页所在视图控制器的侧滑返回功能可实现,需要再修复其失效的问题。
  26. #pragma mark - 让自定义的导航栏左侧按钮支持侧滑手势的处理
  27. - (void)viewWillAppear:(BOOL)animated {
  28. [super viewWillAppear:animated];
  29. if (self.navigationController.viewControllers.count > 1) {
  30. //记录原来的代理
  31. self.delegate = self.navigationController.interactivePopGestureRecognizer.delegate;
  32. //修复手势操作代理
  33. self.navigationController.interactivePopGestureRecognizer.delegate = self;
  34. }
  35. }
  36. - (void)viewWillDisappear:(BOOL)animated {
  37. [super viewWillDisappear:animated];
  38. //把手势代理在传递给原来的代理对象
  39. self.navigationController.interactivePopGestureRecognizer.delegate = self.delegate;
  40. }
  41. - (void)viewDidLoad {
  42. [super viewDidLoad];
  43. // Do any additional setup after loading the view.
  44. self.view.backgroundColor = [UIColor whiteColor];
  45. [self.view addSubview:self.webview];
  46. [self.refreshBarItem class];
  47. [self.view addSubview:self.progressGetView];
  48. [self.view addSubview:self.errorShowView];
  49. //更新左侧按钮
  50. [self updateNavigationItems];
  51. }
  52. -(void)dealloc{
  53. //移除观察者在离开界面的时候
  54. [self.webview removeObserver:self forKeyPath:@"estimatedProgress"];
  55. [self.webview removeObserver:self forKeyPath:@"title"];
  56. }
  57. #pragma mark - delegate or observer
  58. // 页面加载完成之后调用
  59. - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
  60. {
  61. //判断左侧按钮状态
  62. [self updateNavigationItems];
  63. }
  64. // 页面加载失败时调用 开始加载后失败
  65. - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
  66. {
  67. self.title = @"加载失败";
  68. //加载失败时
  69. [self showLoadErrorView];
  70. }
  71. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
  72. if ([keyPath isEqualToString:@"estimatedProgress"]) {
  73. if (object == self.webview) {
  74. self.progressGetView.hidden = NO;
  75. [UIView animateWithDuration:0.1 delay:0.1 options:UIViewAnimationOptionCurveEaseOut animations:^{
  76. self.progressGetView.frame =CGRectMake(0,NAV_HEIGHT,SCREEN_WIDTH*self.webview.estimatedProgress, 3);
  77. } completion:nil];
  78. //下面动画是为了防止加载进度在快速请求另外的网页的时候
  79. //出现进度条回缩的问题
  80. if(self.webview.estimatedProgress >= 1.0f) {
  81. [UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionCurveEaseOut animations:^{
  82. } completion:^(BOOL finished) {
  83. self.progressGetView.frame =CGRectMake(0,NAV_HEIGHT,0, 3);
  84. self.progressGetView.hidden = YES;
  85. }];
  86. }
  87. }
  88. }else if ([keyPath isEqualToString:@"title"])
  89. {
  90. if (object == self.webview) {
  91. self.title = self.webview.title;
  92. }
  93. }
  94. }
  95. //两个手势代理是为了让界面响应侧滑手势
  96. - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
  97. return self.navigationController.viewControllers.count > 1;
  98. }
  99. - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
  100. return self.navigationController.viewControllers.count > 1;
  101. }
  102. #pragma mark - pravite method
  103. -(void)setUrlString:(NSString *)urlString{
  104. _urlString = urlString;
  105. NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
  106. [self.webview loadRequest:request];
  107. }
  108. //更新左侧按钮
  109. -(void)updateNavigationItems{
  110. self.errorShowView.hidden = YES;
  111. if (self.webview.canGoBack) {
  112. [self.navigationItem setLeftBarButtonItems:@[self.customBackBarItem,self.closeButtonItem] animated:NO];
  113. }else{
  114. self.navigationController.interactivePopGestureRecognizer.enabled = YES;
  115. [self.navigationItem setLeftBarButtonItems:@[self.customBackBarItem]];
  116. }
  117. }
  118. -(void)customBackItemClicked{
  119. //如果可以返回 则返回网页上一级
  120. if (self.webview.goBack) {
  121. [self.webview goBack];
  122. }else{
  123. [self closeItemClicked];
  124. }
  125. }
  126. -(void)closeItemClicked{
  127. //移除js监控 要在pop界面之前 不然会内存泄露
  128. //[self popControllerDealloc];
  129. [self.navigationController popViewControllerAnimated:YES];
  130. }
  131. -(void)refreshClicked{
  132. [self.webview reload];
  133. self.errorShowView.hidden = YES;
  134. }
  135. -(void)errorRefreshClick{
  136. [self.webview reload];
  137. self.errorShowView.hidden = YES;
  138. }
  139. //当加载网页失败后 展示加载失败界面
  140. - (void)showLoadErrorView{
  141. self.errorShowView.hidden = NO;
  142. }
  143. #pragma mark - lazy load
  144. -(UIBarButtonItem *)customBackBarItem{
  145. if (!_customBackBarItem) {
  146. //自定义左侧返回按钮
  147. _customBackBarItem = [[UIBarButtonItem alloc]
  148. initWithImage:[UIImage imageNamed:@"nav_btn_back_black"]
  149. style:UIBarButtonItemStylePlain
  150. target:self
  151. action:@selector(customBackItemClicked)];
  152. }
  153. return _customBackBarItem;
  154. }
  155. -(UIBarButtonItem*)closeButtonItem{
  156. if (!_closeButtonItem) {
  157. _closeButtonItem = [[UIBarButtonItem alloc]
  158. initWithImage:[UIImage imageNamed:@"icon_close"]
  159. style:UIBarButtonItemStylePlain
  160. target:self
  161. action:@selector(closeItemClicked)];
  162. [_closeButtonItem setImageInsets:UIEdgeInsetsMake(0, -8, 0, 0)];
  163. }
  164. return _closeButtonItem;
  165. }
  166. -(UIBarButtonItem *)refreshBarItem{
  167. if (!_refreshBarItem) {
  168. _refreshBarItem = [[UIBarButtonItem alloc]
  169. initWithImage:[UIImage imageNamed:@"icon_fresh"]
  170. style:UIBarButtonItemStylePlain
  171. target:self
  172. action:@selector(refreshClicked)];
  173. self.navigationItem.rightBarButtonItem = _refreshBarItem;
  174. }
  175. return _refreshBarItem;
  176. }
  177. -(WKWebView *)webview{
  178. if (!_webview) {
  179. _webview = [[WKWebView alloc]initWithFrame:CGRectMake(0, NAV_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT-NAV_HEIGHT)];
  180. _webview.navigationDelegate = self;
  181. _webview.UIDelegate = self;
  182. //侧滑返回上层
  183. _webview.allowsBackForwardNavigationGestures = YES;
  184. //观察进度变化
  185. [_webview addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionOld context:NULL];
  186. //观察网页标题
  187. [_webview addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
  188. }
  189. return _webview;
  190. }
  191. -(UIView *)progressGetView
  192. {
  193. if (!_progressGetView) {
  194. _progressGetView = [[UIView alloc]init];
  195. _progressGetView.frame =CGRectMake(0, NAV_HEIGHT,0 , 3);
  196. _progressGetView.backgroundColor = LMRGBAColor(67, 138, 230, 1);
  197. }
  198. return _progressGetView;
  199. }
  200. -(UIView *)errorShowView{
  201. if (!_errorShowView) {
  202. _errorShowView = [[UIView alloc]init];
  203. _errorShowView.backgroundColor = [UIColor whiteColor];
  204. _errorShowView.frame = CGRectMake(0, NAV_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT-NAV_HEIGHT);
  205. UIButton * refreshButton = [[UIButton alloc]init];
  206. refreshButton.bounds = CGRectMake(0, 0, 120, 44);
  207. refreshButton.layer.masksToBounds = YES;
  208. refreshButton.layer.cornerRadius = 22;
  209. refreshButton.layer.borderColor = [UIColor blackColor].CGColor;
  210. refreshButton.layer.borderWidth = 1;
  211. [refreshButton setTitle:@"刷新" forState:UIControlStateNormal];
  212. [refreshButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  213. refreshButton.titleLabel.font = [UIFont boldSystemFontOfSize:17];
  214. [refreshButton addTarget:self action:@selector(errorRefreshClick) forControlEvents:UIControlEventTouchUpInside];
  215. [_errorShowView addSubview:refreshButton];
  216. refreshButton.center = CGPointMake(SCREEN_WIDTH/2, SCREEN_HEIGHT/2-NAV_HEIGHT+22+80);
  217. UILabel * showLabel = [[UILabel alloc]init];
  218. showLabel.numberOfLines = 0;
  219. showLabel.font = [UIFont systemFontOfSize:16];
  220. showLabel.textColor = LMRGBAColor(0, 0, 0, 0.48);
  221. showLabel.text =@"当前网络状态不佳,您可以尝试点击下方按钮刷新重试O~";
  222. showLabel.bounds = CGRectMake(0, 0, SCREEN_WIDTH-88, 1);
  223. [showLabel sizeToFit];
  224. [_errorShowView addSubview:showLabel];
  225. showLabel.frame =CGRectMake(44, CGRectGetMinY(refreshButton.frame)-60-showLabel.bounds.size.height, showLabel.bounds.size.width, showLabel.bounds.size.height);
  226. UILabel * errorLabel = [[UILabel alloc]init];
  227. errorLabel.font = [UIFont boldSystemFontOfSize:18];
  228. errorLabel.textColor = LMRGBAColor(0, 0, 0, 0.8);
  229. errorLabel.text =@"很抱歉,加载失败了";
  230. errorLabel.textAlignment = NSTextAlignmentCenter;
  231. [_errorShowView addSubview:errorLabel];
  232. errorLabel.frame =CGRectMake(0, CGRectGetMinY(showLabel.frame)-20-18, SCREEN_WIDTH, 18);
  233. _errorShowView.hidden = YES;
  234. }
  235. return _errorShowView;
  236. }
  237. @end