嘗試實現 Web 上的看圖模式

iOS 上有很多瀏覽器都有“看圖模式”這一功能,實現這一功能可能有很多種途徑,最近接觸到了這方面的工作,所以在此把我的思路記錄下來。過程雖然比較簡短,但日後可能會用到,如有更好的方案也可以對比下,取長補短。

這次並不會用到什麼新特性(比如 WKWebView)。而且方案很簡單,分三步:

  1. 獲取網頁中的圖片(鏈接)
  2. 將圖片(鏈接)傳給圖片查看器
  3. 完成點擊圖片的回調及動畫

這裏不可避免的會要用到 Javascript 來獲取 <img> 元素內容,添加點擊事件等。第一步很簡單,幾行 js 代碼搞定:

1
2
3
4
5
6
7
8
9
function getAllImageUrl(){
var imgs = document.getElementsByTagName("img");
var urlArray = [];
for (var i=0;i<imgs.length;i++){
var src = imgs[i].src;
urlArray.push(src);
}
return urlArray.toString();
}

第二步也不難,因爲圖片查看器可以用現成的第三方庫,比如 IDMPhotoBrowser,只需要傳入一個 NSURL 數組就行。

第三步需要繞個彎子。

首先是用 js 給圖片添加點擊事件,這個簡單:

1
2
3
4
5
6
function setImage(){
var imgs = document.getElementsByTagName("img");
for (var i=0;i<imgs.length;i++){
imgs[i].setAttribute("onClick","imageClick("+i+")");
}
}

然後是動畫,還好 IDMPhotoBrowser 提供了一個動畫的接口:

1
- (id)initWithPhotos:(NSArray *)photosArray animatedFromView:(UIView*)view

這裏需要傳入一個 view 來作爲動畫的起始參數。我的做法是在 webView 上添加一個佔位視圖,並正好覆蓋在被點擊圖片之上,將其作爲動畫的起始參數。這就需要從網頁上獲取被點擊圖片的 frame,還有圖片的內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getImageRect(i){
var imgs = document.getElementsByTagName("img");
var rect;
rect = imgs[i].getBoundingClientRect().left+"::";
rect = rect+imgs[i].getBoundingClientRect().top+"::";
rect = rect+imgs[i].width+"::";
rect = rect+imgs[i].height;
return rect;
}
function getImageData(i){
var imgs = document.getElementsByTagName("img");
var img=imgs[i];
var canvas=document.createElement("canvas");
var context=canvas.getContext("2d");
canvas.width=img.width; canvas.height=img.height;
context.drawImage(img,0,0,img.width,img.height);
return canvas.toDataURL("image/png")
}

在獲取圖片內容時我並沒有通過圖片的 url 在 OC 代碼中重新下載一次圖片,而是選擇將 web 中已經下載好的圖片轉成 png 格式傳給 OC。但 stringByEvaluatingJavaScriptFromString: 方法返回的都是字符串,而且 js 返回的數據編碼還是 base64 格式的。這裏用到 skpsmtpmessage 這個第三方庫將其解碼爲 NSData

1
2
3
4
5
6
NSString *javascript = [NSString stringWithFormat:
@"getImageData(%d);", imgIndex];

NSString *stringData = [webView stringByEvaluatingJavaScriptFromString:javascript];
stringData = [stringData substringFromIndex:22]; // strip the string "data:image/png:base64,"

NSData *data = [NSData decodeWebSafeBase64ForString:stringData];
UIImage *image = [UIImage imageWithData:data];

嗯,最後完成圖片點擊事件的函數,在其中獲取被點擊圖片的 frame,並拼湊成以 “clickgirl” 開頭的 url,當然如果你喜歡用 “sexualgirl” 之類的也可以:

1
2
3
4
5
function imageClick(i){
var rect = getImageRect(i);
var url="clickgirl::"+i+"::"+rect;
document.location = url;
}

上面的 url 在 UIWebViewDelegate 的 - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType中會獲取到,我貼上完整代碼,順便去掉下討厭的百度推廣。不要忘了在 browser 出現後將佔位圖片移除:

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
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *requestString = [[request URL] absoluteString];
if ([requestString hasPrefix:@"http://pos.baidu.com"]) {// ignore baidu ad
return NO;
}
NSArray *components = [requestString componentsSeparatedByString:@"::"];
if ([components[0] isEqualToString:@"clickgirl"]) {
int imgIndex = [components[1] intValue];
CGRect frame = CGRectMake([components[2] floatValue], [components[3] floatValue], [components[4] floatValue], [components[5] floatValue]);
UIImageView *showView = [[UIImageView alloc] initWithFrame:frame];
NSString *javascript = [NSString stringWithFormat:
@"getImageData(%d);", imgIndex];
NSString *stringData = [webView stringByEvaluatingJavaScriptFromString:javascript];
stringData = [stringData substringFromIndex:22]; // strip the string "data:image/png:base64,"
NSData *data = [NSData decodeWebSafeBase64ForString:stringData];
UIImage *image = [UIImage imageWithData:data];
showView.image = image;
[_webView addSubview:showView];

NSString *urls = [_webView stringByEvaluatingJavaScriptFromString:@"getAllImageUrl();"];
IDMPhotoBrowser *browser = [[IDMPhotoBrowser alloc] initWithPhotos:[IDMPhoto photosWithURLs:[urls componentsSeparatedByString:@","]] animatedFromView:showView];
[browser setInitialPageIndex:imgIndex];
browser.useWhiteBackgroundColor = YES;
[self presentViewController:browser animated:YES completion:nil];
[showView removeFromSuperview];

}
return YES;
}

其實有些網站只是在手機站上加了百度推廣之類的,而在 PC 端可能並沒有。至於符合查看手機上 web 的佈局,可以在調試時打開 Mac 上的 Safari,點擊“開發”菜單(我相信你肯定早已開啓開發模式),選擇你調試的那臺設備,然後會看到你正在調試的程序和 webview 當前打開的域名。點擊後可以展開 Web 檢查器,使用方法跟 Mac 上 Safari 的 Web 檢查器一樣: 

Web 檢查器Web 檢查器

這樣就可以查看手機上的 Web 元素,方便我們 js 代碼的編寫。

其實在做公司項目時看了下 IDMPhotoBrowser 的代碼,並做了一點兒優化和定製,尤其是在動畫方面,這個控件還有很多流程和性能優化的空間。

最後放上 Demo 的 Github:https://github.com/yulingtianxia/WebViewImageClick

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章