1. 程式人生 > >ios UIWebview 載入頁面(詳解二)

ios UIWebview 載入頁面(詳解二)

設定背景透明

  • 設定webview的backgroundColor屬性為[UIColor clearColor];

    ?
    1 webView.backgroundColor = [UIColor clearColor];
  • 為webview中的HTML頁面的body標籤新增CSS背景樣式設定

    ?
    1 2 3 <body style="background-color: transparent"> ... </body>
  • 設定webview的opaque屬性值為NO

    ?
    1 webView.opaque = NO;

載入本地HTML頁面

  1. 方式一

    ?
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 NSString *localHTMLPageName = @"myPage"; NSString *path = [[NSBundle mainBundle] pathForResource:localHTMLPageName ofType:@"html"]; // 從html檔案中讀取html字串 NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:path]; NSString *htmlString = [[NSString alloc] initWithData:
    [readHandle readDataToEndOfFile] encoding:NSUTF8StringEncoding]; // 或使用                 // NSString *htmlString = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL]; // baseURL用來確定htmlString的基準地址, // 相當於HTML的<base>標籤的作用,定義頁面中所有連結的預設地址。 [webView loadHTMLString:htmlString baseURL:[[NSBundle mainBundle] bundleURL]];
  2. 方式二

    ?
    1 2 3 4 5 6 7 NSString *localHTMLPageName = @"myPage"; NSString *localHTMLPageFilePath = [[NSBundle mainBundle] pathForResource:localHTMLPageName ofType:@"html"]; NSURL *localHTMLPageFileURL = [NSURL fileURLWithPath:localHTMLPageFilePath]; [webView loadRequest:[NSURLRequest requestWithURL:localHTMLPageFileURL]];

移除滾動後的外邊陰影

UIWebView包含一個scrollView元件,用來將關聯web內容實現滾動效果,頁面滾動後的UIWebView的面板周圍會出現陰影效果,該效果是在四周新增UIImageView實現的,因此移除這種陰影效果的程式碼如下:

?
1 2 3 4 5 6 7 8 UIScrollView *scrollView = webView.scrollView; for (int i = 0; i < scrollView.subviews.count ; i++) { UIView *view = [scrollView.subviews objectAtIndex:i]; if ([view isKindOfClass:[UIImageView class]]) { view.hidden = YES ; } }

在Safari中開啟連結地址

預設情況下,長按web頁面中的連結,系統會自動撥出選單提供open,copy和cancel選項,但如果要實現觸擊連結跳轉至safari中開啟頁面該怎麼做呢?UIWebViewDelegate協議中,包含

?
1 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

介面,如果為webView添加了delegate物件並實現該介面,那麼在webView載入任何一個frame之前都會delegate物件的該方法,該方法的返回值用以控制是否允許載入目標連結頁面的內容,返回YES將直接載入內容,NO則反之。並且UIWebViewNavigationType列舉,定義了頁面中使用者行為的分類,包括

  • UIWebViewNavigationTypeLinkClicked,使用者觸擊了一個連結。
  • UIWebViewNavigationTypeFormSubmitted,使用者提交了一個表單。
  • UIWebViewNavigationTypeBackForward,使用者觸擊前進或返回按鈕。
  • UIWebViewNavigationTypeReload,使用者觸擊重新載入的按鈕。
  • UIWebViewNavigationTypeFormResubmitted,使用者重複提交表單
  • UIWebViewNavigationTypeOther,發生其它行為。

因此,實現使用者觸擊UIWebView頁面中的連結,並跳至Safari中開啟連結頁面的步驟如下:

  1. 定義實現UIWebViewDelegate協議的類MyWebViewDelegate(通常是由包含UIWebView的controller中實現UIWebViewDelegate協議)。

  2. 按如下方式實現webView:shouldStartLoadWithRequest:navigationType:介面

    ?
    1 2 3 4 5 6 7 8 9 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if ( navigationType == UIWebViewNavigationTypeLinkClicked ) { [[UIApplication sharedApplication] openURL:[request URL]]; return NO; } return YES; }
  3. 新建MyWebViewDelegate物件,並賦值給webView的delegate屬性

禁用頁面滾動彈跳

之前提到UIWebView使用一個UIScrollView物件來關聯web頁面的內容,通過UIWebView的scrollView屬性即可獲得該物件,預設情況下網頁長度超出裝置視口長度後頁面會滾動,使用者使用手指滾動頁面到頁面邊距並放開手指後頁面會產生一個彈跳效果,去除這個效果的方法如下

?
1 webView.scrollView.bounces = NO ;

scalesPageToFit屬性

預設情況下UIWebView載入HTML頁面後,會以頁面的原始大小進行顯示,亦即如果頁面的大小超出UIWebView視口大小,UIWebView會出現滾動效果,而且使用者只能通過滾動頁面來檢視不同區域的內容,不能使用手指的捏合手勢來放大或縮小頁面。通過設定

?
1 webView.scalesPageToFit = YES ;

UIWebView可以縮放HTML頁面來適配其視口大小,從而達到整屏顯示內容的效果,並且使用者可以用捏合動作來放大或縮小頁面來檢視內容。

呼叫javascript程式碼

UIWebView提供

?
1 - (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script

方法,可以在objective-c程式碼中呼叫javascript程式碼,引數script字串儲存了所要執行的js程式碼字串,執行結果以字串形式返回。以獲取web頁面標題為例,程式碼如下:

?
1 NSString *pageTitle = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

指令碼的程式碼內容還要依據具體的應用場景。此外,該方法規定執行的指令碼時長限定在10s內,為的是防止過長時間的阻塞頁面主執行緒,超過執行時間上線會自動停止指令碼執行,並且指令碼可分配記憶體限定在10MB內,超過分配上線將會引發異常。

javascript呼叫native程式碼

以上提到,UIWebView載入任何一個頁面之前都會呼叫其代理的

?
1 2 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

方法,通過呼叫引數request物件的URL屬性來獲取關於本次請求的地址以及引數資訊,因此可以通過js程式碼模擬一次特殊的網路請求來達到呼叫該代理方法的作用,並通過過濾“特殊的url”來達到有目的性的js程式碼呼叫native程式碼的效果。所謂的“特殊的url”主要的目的是達到一種標識的效果,我們可以規定url的scheme部分,如appscheme://appName?invokeMethodName=objcMethod&amp;paramA=xxx;也可以在常規的url後面附加特殊的引數標識,如http://www.yoursite.com?objecMethodCallFlag=1&methodName=methodA&amp;paramA=xxx。之後根據規定在代理方法中去相應的解析url並做出if else判斷即可。常見的呼叫方式是動態新增一個隱藏的iframe標籤到HTML頁面,如下:

?
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 // js function invokeObjc(url) { var iframe; iframe = document.createElement("iframe"); iframe.setAttribute("src", url); iframe.setAttribute("style", "display:none;"); document.body.appendChild(iframe); iframe.parentNode.removeChild(iframe); } var url = "appscheme://appName?invokeMethodName=objcMethod&paramA=xxx"; invokeObjc(url); // objc - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType static NSString *callScheme = @"appscheme"; static NSString *invokeMethodName = @"invokeMethodName"; NSString *scheme = request.URL.scheme ; if ([callScheme isEqualToString:scheme]) { NSString *query = request.URL.query ; NSArray *arr = [query componentsSeparatedByString:@"&"]; __block NSString *methodName = @"" ; NSMutableDictionary *params = [NSMutableDictionary new]; // 未考慮引數的解碼操作 [arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSArray *kv =[obj componentsSeparatedByString:@"="]; if (kv) { if ([invokeMethodName isEqualToString: kv[0]]) { methodName = kv[1]; }else{ [params setObject:kv[1] forKey:kv[0]]; } } }]; // 獲得方法名和引數之後,可以新增邏輯判斷 NSLog(@"%@",methodName); NSLog(@"%@",params); return NO ; } return YES ;

前面提到的native程式碼呼叫js程式碼的實現方式,結合兩種實現方式即完成了js與native程式碼間的簡單的通訊操作。

讓UIWebView更加接近native

某些情況下,我們既想要UIWebView載入web頁面,又想使得所載入的頁面的外觀和操作行為更加接近native感覺。這時需要使用一些CSS樣式來達到這些效果,這些CSS只適用於IOS中的Safari。

  • -webkit-touch-callout

    禁用長按觸控物件彈出的選單。IOS中,當你長按一個觸控物件時,如連結,safari會彈出包含連結資訊的選單。禁用此行為CSS程式碼

    ?
    1 2 3 .disable-callout{ -webkit-touch-callout:none ; }

    或在webViewDidFinisheLoad中使用

    ?
    1 [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
  • -webkit-user-select

    控制使用者是否可以選擇頁面元素內容。IOS中,在頁面元素中進行長按操作,safari會彈出選單,來允許進行選擇行為。禁用此行為程式碼

    ?
    1 2 3 .disable-select{ -webkit-user-select:none; }

    或在webViewDidFinisheLoad中使用

    ?
    1 [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
  • -webkit-tap-highlight-color

    覆蓋當用戶tap連結或clickable元素時預設產生的高亮顏色(灰色)。如

    ?
    1 2 3 .no-highlight{ -webkit-tap-highlight-color:rgba(0,0,0,0); }