iOS WKWebView UI增強(上拉重新整理,JS互動,載入進度條)

小東邪發表於2018-11-06

需求:WKWebView的一些增加模組,例如上拉重新整理,JS互動,載入進度條等等持續更新


閱讀前提:

  • 瞭解WKWebView基本初始化及使用

GitHub地址(附程式碼) : iOS WKWebView UI增強

簡書地址 : iOS WKWebView UI增強

部落格地址 : iOS WKWebView UI增強

掘金地址 : iOS WKWebView UI增強


使用WKWebView需要在專案匯入WebKit.framework以及Info.plist檔案中新增許可權

<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsArbitraryLoads</key>
		<true/>
	</dict>
複製程式碼

1. 與JS互動

如需與JS互動可在初始化時配置WKWebViewConfiguration物件,然後註冊[[_webView configuration].userContentController addScriptMessageHandler:self name:@"getMessage"];

如上我們新增了一個名為getMessage的通知,例如,前端頁面裡有一個登陸按鈕,前端小夥伴僅僅需要在登陸方法的最後加上如下程式碼即可在使用者點選前端介面的登陸按鈕時通知我們,注意getMessage兩端必須一致!

try {
    window.webkit.messageHandlers.getMessage.postMessage(jsonStr)
} catch(error) {
    console.log(error)
}
複製程式碼

然後我們即可通過該方法接收到前端頁面上某次點選事件

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    log4cplus_info("XDX_LOG", "%s - %s receive the message name is %s, message content is %s.", ModuleName, __func__,[NSString stringWithFormat:@"%@",message.name].UTF8String, [NSString stringWithFormat:@"%@",message.body].UTF8String);
}
複製程式碼

2. 上拉重新整理

2-1 .如需上拉重新整理功能,可直接使用MJRefresh,僅僅在初始化時如下配置即可,然後在didStartProvisionalNavigation開始載入網頁時結束重新整理即可。

    TVUMJRefreshNormalHeader *header = [TVUMJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(headerRefresh)];
    [header setTitle:@"Pull down to refresh" forState:TVUMJRefreshStateIdle];
    [header setTitle:@"Release to refresh" forState:TVUMJRefreshStatePulling];
    [header setTitle:@"Loading ..." forState:TVUMJRefreshStateRefreshing];
    header.lastUpdatedTimeLabel.hidden = YES;
    self.webView.scrollView.mj_header = header;
    
- (void)headerRefresh{
    // If user enter our app (not network), the URL is NULL even if we have already setted.
    if (!self.webView.URL) {
        log4cplus_error("XDX_LOG", "Refresh webview error, current URL is NULL !");
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.yourWebAddress] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:XDX_URL_TIMEOUT];
        [self.webView loadRequest:request];
    }
    [self.webView reload];
}

- (void)endRefresh{
    [self.webView.scrollView.mj_header endRefreshing];
}

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    [self endRefresh];
}



複製程式碼

2-2. 注意,因為WKWebview內部的UIScrollView與上滑手勢衝突,所以我們還需要實現重寫下面方法,該方法表示如果與前端頁面手勢衝突則雙方都將執行

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

複製程式碼

3. 進度條載入

3-1. 初始化UIProgressView

@property (nonatomic, strong) UIProgressView    *progressView;

    self.progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 0.8)];
    self.progressView.progressTintColor = [UIColor greenColor];
    //設定進度條的高度,下面這句程式碼表示進度條的寬度變為原來的1倍,高度變為原來的1.5倍.
    self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f);
    [self.webView addSubview:self.progressView];
    
複製程式碼

3-2. 當網頁載入時顯示ProgressView

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
    [self endRefresh];
    
    if ([self.progressView isDescendantOfView:self.webView]) {
        self.progressView.hidden = NO;
        self.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.5f);
    }
}
複製程式碼

3-3. 為webView新增通知 [self.webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];

3-3. 在通知中檢測是否載入完成時進度條消失

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    if ([self.progressView isDescendantOfView:self.webView]) {
        if ([keyPath isEqualToString:@"estimatedProgress"]) {
            self.progressView.progress = self.webView.estimatedProgress;
            if (self.progressView.progress == 1) {
                /*
                 *新增一個簡單的動畫,將progressView的Height變為1.4倍,在開始載入網頁的代理中會恢復為1.5倍
                 *動畫時長0.25s,延時0.3s後開始動畫
                 *動畫結束後將progressView隱藏
                 */
                
                __weak ViewController *weakSelf = self;
                [UIView animateWithDuration:0.25f delay:0.3f options:UIViewAnimationOptionCurveEaseOut animations:^{
                    weakSelf.progressView.transform = CGAffineTransformMakeScale(1.0f, 1.4f);
                } completion:^(BOOL finished) {
                    weakSelf.progressView.hidden = YES;
                    
                }];
            }
        }else{
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
}
複製程式碼

相關文章