思路:safari 自带了长按保存的功能,分析这个功能的特点: 长按一个图片,保存后的图片就是所点击的图片,做到了精确定位。JS可以处理精确定位的问题,使用UIWebview 和 JS 能够解决我们的问题。
直接上代码
UIWebView *aWebView = [[UIWebView alloc] initWithFrame:CGRectMake(0.0, 0, [[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height)]; aWebView.delegate = self; aWebView.scalesPageToFit = YES; self.mainWebView = aWebView; [self.view addSubview:aWebView]; NSURLRequest *request =[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://image.baidu.com/"] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:20]; [self.mainWebView loadRequest:request]; UILongPressGestureRecognizer *longtapGesture = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longtap:)]; [self.view addGestureRecognizer:longtapGesture];
添加webview,添加长按手势,看起来没有什么。
-(void)longtap:(UILongPressGestureRecognizer * )longtapGes{ if (longtapGes.state == UIGestureRecognizerStateBegan) { CGPoint pt = [longtapGes locationInView:self.view]; pt= [self.mainWebView convertPoint:pt fromView:nil]; CGPoint offset = [self.mainWebView.scrollView contentOffset]; CGSize viewSize = [self.view frame].size; CGSize windowSize = [self.view frame].size; CGFloat f = windowSize.width / viewSize.width; pt.x = pt.x * f + offset.x; pt.y = pt.y * f + offset.y; [self openContextualMenuAt:pt]; } }
注意看下这段代码
pt 为映射在webview 上的坐标
得到坐标后,根据contentOffset,获取到点击的坐标上在 web 绝对位置上的坐标点。
- (void)openContextualMenuAt:(CGPoint)pt { NSString *path = [[NSBundle mainBundle] pathForResource:@"test1" ofType:@"txt"]; NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; [self.mainWebView stringByEvaluatingJavaScriptFromString: jsCode]; NSString *tags = [self.mainWebView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat:@"MyAppGetHTMLElementsAtPoint(%i,%i);",(NSInteger)pt.x,(NSInteger)pt.y]]; UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Contextual Menu" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil]; if ([tags rangeOfString:@",A,"].location != NSNotFound) { [sheet addButtonWithTitle:@"打开链接"]; } if ([tags rangeOfString:@",IMG,"].location != NSNotFound) { NSString *str = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", pt.x, pt.y]; NSString *imgStr= [self.mainWebView stringByEvaluatingJavaScriptFromString: str]; NSLog(@"启动一个request下载图片:%@",imgStr); [sheet addButtonWithTitle:@"保存图片"]; } [sheet addButtonWithTitle:@"在Safari中打开"]; [sheet showInView:self.view]; }
test1.txt 内容如下
function MyAppGetHTMLElementsAtPoint(x,y) { var tags = ","; var e = document.elementFromPoint(x,y); while (e) { if (e.tagName) { tags += e.tagName + ','; } e = e.parentNode; } return tags; }
这段js 能够返回 web 内容坐标对应 web 节点
然后通过注入方式调用js,并获取到图片地址
NSString *str = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", pt.x, pt.y]; NSString *imgStr= [self.mainWebView stringByEvaluatingJavaScriptFromString: str];
到这里,我们的任务已经完成了大半了。
还需要做的是弹出选择框,用户选择操作,代码实现选择操作。此处省略若干代码和说明。
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { // 这里实际启动request,下载图片 // 我看见UC 浏览器断网也是可以下载图片的,我大概知道是通过JS,但具体操作就不知道了,有没有人知道是怎么实现的,分享下 } -(void)webViewDidFinishLoad:(UIWebView *)webView { [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"]; [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"]; }
这里 webview 一旦加载完成了,通过JS注入,这段js 直接去除了点击和选中效果,否则会出现uiwebview 自带copy 工具,以及选中变灰的效果。
总结:
在webview 加载完成之后,禁用掉webview自带的选择和长按事件。
在外部添加长按事件,并映射成webview中长按事件所处的位置px
在通过调用stringByEvaluatingJavaScriptFromString:@""方法获取到上步中px所处位置的 html 节点
同样通过调用stringByEvaluatingJavaScriptFromString:@""方法得到节点的 src 信息
新开请求去获得图片
我看见UC 浏览器断网也是可以下载图片的,我大概知道是通过JS,但具体操作就不知道了,有没有人知道是怎么实现的,分享下
DEMO下载地址:https://github.com/chexsong/WorkingDemos
车小松(http://blog.csdn.net/mangosnow)
本文遵循“署名-非商业用途-保持一致”创作公用协议