UI基础 - WKWebView

前言

1 - 从 iOS 8 开始就引入了新的浏览器控件 WKWebView,用于取代 UIWebView!优点如下

① 内存开销更小

② 内置手势

③ 支持更多 H5 特性

④ 有 Safari 相同的 JavaScript 引擎

⑤ 提供更多属性。比如加载进度、标题、准确的得到页面数等等

⑥ 提供了更精细的加载流程回调

⑦ WKWebView 的流程粒度更加细致,不但在请求的时候会询问 WKWebView 是否请求数据,还会在返回数据之后询问 WKWebView 是否加载数据

2 - UIWebView 和 WKWebView

WKWebView

1 - 如何使用 WKWebView

  1 #import "ViewController.h"
  2 #import <WebKit/WebKit.h> // 需要引入头文件
  3 @interface ViewController ()<WKNavigationDelegate,WKUIDelegate>
  4 
  5 @property(nonatomic,strong)WKWebView *webView;
  6 @property(nonatomic,strong)UIProgressView *progressView;
  7 
  8 @end
  9 
 10 @implementation ViewController
 11 
 12 - (void)viewDidLoad {
 13     [super viewDidLoad];
 14     self.view.backgroundColor = [UIColor blackColor];
 15 
 16     // 获取已打开页面数量
 17     // UIWebView 提供了 pagecount,但是没有卵用! WKWebView 中的 backList 记录了可回退的页面信息
 18     // 已打开页面数量 = backList.count + 当前页
 19     int pageCount = self.webView.backForwardList.backList.count  + 1;
 20     
 21     // 进度条
 22     self.progressView.hidden = NO;
 23     [self progressBarLoading];
 24     
 25     // 加载本地PDF文件
 26     NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Demo22P" ofType:@"pdf"];
 27     NSURL *url = [NSURL fileURLWithPath:filePath];
 28     NSURLRequest *request = [NSURLRequest requestWithURL:url];
 29     [self.webView loadRequest:request];
 30 }
 31 #pragma mark - H5页面 标题更换
 32 -(void)renewTitle{
 33     // 导航栏标题经常要根据当前 H5页面 标题更换
 34     // 以前都是在页面加载完成后,使用 window.document.title 来获取
 35     // 现在 WKWebView 提供了相关字段,我们只需要监听这个字段即可
 36     [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:NULL];
 37 }
 38 
 39 #pragma mark - 动态加载进度条
 40 -(void)progressBarLoading{
 41     // 早期的 UIWKWebView 无法获取加载进度,只能知晓开始加载和结束加载
 42     // 因此以前的做法是做一个假的进度条,等到结束的时候再突然设置成 100%
 43     
 44     // WKWebView 提供了 estimatedProgress来监听加载进度,提供了 loading 来获取加载状态
 45     // 我们可以拖个 UIProgressView 来显示进度(也很多人用 layer 实现,还可以做渐变的效果,视觉上更优)
 46     [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:NULL];
 47     [self.webView addObserver:self forKeyPath:@"loading" options:NSKeyValueObservingOptionNew context:NULL];
 48 }
 49 #pragma mark - 监听方法
 50 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
 51     
 52     //---------------------- H5页面 标题更换
 53     if ([keyPath isEqualToString:@"title"]) {
 54         NSString *title = (NSString *)change[NSKeyValueChangeNewKey];
 55         self.title = title;
 56     }
 57     
 58     //---------------------- 动态加载进度条
 59     if ([keyPath isEqualToString:@"estimatedProgress"]) {
 60         CGFloat estimatedProgress = [change[NSKeyValueChangeNewKey] floatValue];
 61         NSLog(@"页面加载进度:%f", estimatedProgress);
 62         [self.progressView setProgress:estimatedProgress];
 63     }else if ([keyPath isEqualToString:@"loading"]) {
 64         BOOL loading = [change[NSKeyValueChangeNewKey] boolValue];
 65         NSLog(@"%@", loading ? @"开始加载" : @"停止加载");
 66         //self.progressView.hidden = !loading; // 是否隐藏进度条
 67     }
 68 }
 69 
 70 #pragma mark - 懒加载
 71 - (WKWebView *)webView{
 72     if (_webView == nil) {
 73         
 74         // 初始化配置定制
 75         WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
 76         // 用户拷贝网页内容的时候的粒度
 77         configuration.selectionGranularity = WKSelectionGranularityDynamic;
 78         // 允许在网页内部播放视频
 79         configuration.allowsInlineMediaPlayback = YES;
 80         
 81         WKPreferences *preferences = [WKPreferences new];
 82         // 是否支持 JavaScript
 83         preferences.javaScriptEnabled = YES;
 84         // 不通过用户交互,是否可以打开窗口
 85         preferences.javaScriptCanOpenWindowsAutomatically = YES;
 86         configuration.preferences = preferences;
 87         
 88         // WKWebView
 89         _webView = [[WKWebView alloc] initWithFrame:CGRectMake(0, [UIApplication sharedApplication].statusBarFrame.size.height+10+10+20, self.view.frame.size.width, self.view.frame.size.height - [UIApplication sharedApplication].statusBarFrame.size.height-40-20) configuration:configuration];
 90         [self.view addSubview:_webView];
 91         // 有两种代理:UIDelegate负责界面弹窗;navigationDelegate负责加载、跳转等
 92         _webView.UIDelegate = self;
 93         _webView.navigationDelegate = self;
 94     }
 95     return _webView;
 96 }
 97 
 98 // 进度条
 99 -(UIProgressView *)progressView{
100     if(_progressView == nil){
101         _progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(50, [UIApplication sharedApplication].statusBarFrame.size.height+10, self.view.frame.size.width-50*2, 20)];
102         //进度条类型
103         [_progressView setProgressViewStyle:UIProgressViewStyleDefault];
104         [self.view addSubview:_progressView];
105     }
106     return _progressView;
107 }
108 
109 #pragma mark - <WKNavigationDelegate>
110 /* 页面开始加载 */
111 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
112 }
113 /* 开始返回内容 */
114 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
115     
116 }
117 /* 页面加载完成 */
118 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
119     
120 }
121 /* 页面加载失败 */
122 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation{
123     
124 }
125 /* 在发送请求之前,决定是否跳转 */
126 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{
127     // 允许跳转
128     decisionHandler(WKNavigationActionPolicyAllow);
129     // 不允许跳转
130     //decisionHandler(WKNavigationActionPolicyCancel);
131 }
132 /* 在收到响应后,决定是否跳转 */
133 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
134     
135     NSLog(@"decidePolicyForNavigationResponse = %@",navigationResponse.response.URL.absoluteString);
136     // 允许跳转
137     decisionHandler(WKNavigationResponsePolicyAllow);
138     // 不允许跳转
139     //decisionHandler(WKNavigationResponsePolicyCancel);
140 }
141 
142 #pragma mark - <WKUIDelegate>
143 // 处理 alert 弹窗事件
144 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
145     
146     // 弹窗
147     [self alert:@"温馨提示" message:message?:@"" buttonTitles:@[@"确认"] handler:^(int index, NSString *title) {
148         completionHandler();
149     }];
150 }
151 
152 // 处理 Confirm 弹窗事件
153 - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
154     
155     [self alert:@"温馨提示" message:message?:@"" buttonTitles:@[@"取消", @"确认"] handler:^(int index, NSString *title) {
156         completionHandler(index != 0);
157     }];
158 }
159 
160 /// 处理 TextInput 弹窗事件
161 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler {
162     
163     UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:prompt preferredStyle:UIAlertControllerStyleAlert];
164     [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
165         textField.text = defaultText;
166     }];
167     [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
168         completionHandler(nil);
169     }]];
170     [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
171         NSString *text = [alert.textFields firstObject].text;
172         NSLog(@"字符串:%@", text);
173         completionHandler(text);
174     }]];
175     [self presentViewController:alert animated:YES completion:nil];
176 }
177 
178 #pragma mark - 自定义弹窗
179 - (void)alert:(NSString *)title message:(NSString *)message {
180     [self alert:title message:message buttonTitles:@[@"确定"] handler:nil];
181 }
182 
183 - (void)alert:(NSString *)title message:(NSString *)message buttonTitles:(NSArray *)buttonTitles handler:(void(^)(int, NSString *))handler {
184     
185     UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
186     
187     for (int i = 0; i < buttonTitles.count; i++) {
188         [alert addAction:[UIAlertAction actionWithTitle:buttonTitles[i] style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
189             if (handler) {
190                 handler(i, action.title);
191             }
192         }]];
193     }
194     [self presentViewController:alert animated:YES completion:nil];
195 }
196 
197 @end

运行效果:PDF文件加载完成

 

posted on 2023-08-31 18:05  低头捡石頭  阅读(168)  评论(0编辑  收藏  举报

导航