iOS UWebView详解
有时在项目中我们需要嵌入一些web相关的内容,这时你就要用到一个叫UIWebView的东西(UIWebView还可以打开一些文件等,如pdf等),在android和iOS中都有这个东西,使用起来也很方便
只要发送一个request加载web content就行,而且它也支持会退和前进,此外,你还可以通过它与网页中的js进行交互,下面看详细讲解。
一、先来看看UIWebView的打开文件的功能,具体支持的文件类型如下:
iPhone OS 2.2.1 supports the following document types:
- Excel (.xls)
- Keynote (.key.zip)
- Numbers (.numbers.zip)
- Pages (.pages.zip)
- PDF (.pdf)
- Powerpoint (.ppt)
Word (.doc)
iPhone OS 3.0 supports these additional document types:
- Rich Text Format (.rtf)
- Rich Text Format Directory (.rtfd.zip)
- Keynote '09 (.key)
- Numbers '09 (.numbers)
Pages '09 (.pages)
看到了吧,常用的word,execl 、PDF都能打开。加载这些本地数据时,你可以使用loadRequest,或者 loadData:MIMEType:textEncodingName:baseURL:,代码如下:
-(void)loadDocument:(NSString*)documentName inView:(UIWebView*)webView { //这是你要打开的文件的存放路径,也可以是document目录下的路径 NSString *path = [[NSBundle mainBundle] pathForResource:documentName ofType:nil]; //当路径在本地时,就用下面的方法换成url,如果在远程web上,则用 //urlWithString NSURL *url = [NSURL fileURLWithPath:path]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request]; }
NSString *thePath = [[NSBundle mainBundle] pathForResource:@"iPhone_User_Guide" ofType:@"pdf"]; if (thePath) { NSData *pdfData = [NSData dataWithContentsOfFile:thePath]; [(UIWebView *)self.view loadData:pdfData MIMEType:@"application/pdf" textEncodingName:@"utf-8" baseURL:nil]; }
但记住了,如果你要打开的文件很大,那不可使用这种方法打开。
二、当你要加载一些html数据时你可以使用 loadHTMLString:baseURL: 你也可以用上面的方法加载,对于该控件,最大的作用莫非加载网页了,下面详细介绍。。。
1.你可以使用它的方法 loadRequest:加载web content, 停止加载则使用stopLoading,当然,你肯定要知道它是否正在加载,此时你可以通过属性loading进行判断。
2.如果你允许用户向前、向后浏览网页历史纪录时,你可以使用方法goBack 和 goForward,当然在使用上面的方法前,你可以判断是否能继续向前,或向后,canGoBack、canGoForward.
3.UIWebView还具有内容检测功能,当网页内容中出现了一些手机号码、网页链接等东西时,它能够动态识别,如果你点击了它能够识别的东西,则它会进行相应的处理,如:当发现你点击的是电话号码时,则直接拨号,当发现你点击的是网址,则打开浏览器前往链接,但UIWebView默认只会识别电话号码,不过你可以通过设置它的 来dataDetectorTypes属性来设置到底支持那种类型的识别,该属性值可以是下面的这些
UIDataDetectorTypePhoneNumber = 1 << 0, //识别电话号码 UIDataDetectorTypeLink = 1 << 1, //识别网址,链接等 UIDataDetectorTypeAddress = 1 << 2, // 识别地址 UIDataDetectorTypeCalendarEvent = 1 << 3, // 识别时间 UIDataDetectorTypeNone = 0, //全都不识别 UIDataDetectorTypeAll = NSUIntegerMax // 全部识别
你可以用 或"|" 指定识别其中的几种
4.UIWebView具有和UIScrollView一样的放大、缩小功能,你只要设置属性scalesPageToFit,为YES就可以达到效果,正因为如此,所以你的UIWebView 不能嵌入到UIScrollView中去,一般加载网页的代码如下:
[self.myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"]]];
注意了:loadRequest的方法本身就是异步的,所以你不必怕影响性能,自己给他再搞个异步。
5.UIWebView 还有个delegate,主要是用来检测网页的加载,以及与网页中的js实现交互等,与js交互的功能很叼吧,但实现起来可是非常简单,主要是通过它的方法
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *
)script
实现的,你传入的参数,也就是script的js代码不能超过10M 大。
6.下面是一些代码,随便写的,不是很完善。里面也有注释
#import "ViewController.h" @interface ViewController (){ UIWebView *webView; UIButton *backBtn; UIButton *forwardBtn; UIButton *refreshBtn; NSURLRequest *currentRequest; //加载时是否发生error BOOL hasError; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, 320, 400)]; [self.view addSubview:webView]; webView.scalesPageToFit = YES; webView.allowsInlineMediaPlayback = YES; backBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [backBtn setFrame:CGRectMake(10, 420, 80, 30)]; [backBtn setTitle:@"back" forState:UIControlStateNormal]; [backBtn addTarget:self action:@selector(goBack:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:backBtn]; refreshBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [refreshBtn setFrame:CGRectMake(120, 420, 80, 30)]; [refreshBtn setTitle:@"refresh" forState:UIControlStateNormal]; [refreshBtn addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:refreshBtn]; forwardBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect]; [forwardBtn setFrame:CGRectMake(230, 420, 80, 30)]; [forwardBtn setTitle:@"forward" forState:UIControlStateNormal]; [forwardBtn addTarget:self action:@selector(goForward:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:forwardBtn]; //请求链接 currentRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]; hasError = NO; //通过监听web view是否能够向前 或 向后来决定按钮是否可用,就像AVCaptureDevice那样,能监听它自己的属性---adjustFocusing的变化,这样就知道它是否在进行聚焦,后面发现,它压根就不允这样,试想下,如果知道UIWebView能否前进,或后退,然后根据这个来设置前进和后退的按钮是否可用,那多帅啊(当然,我们可以用定时器实现这功能,但总感觉不好),希望以后能这样。。。 [webView addObserver:self forKeyPath:@"canGoBack" options:NSKeyValueObservingOptionNew context:nil]; [webView addObserver:self forKeyPath:@"canGoForward" options:NSKeyValueObservingOptionNew context:nil]; } //在这迷糊了,发现一直监听不到,不像 AVCaptureDevice那样,能监听它自己的属性---adjustFocusing -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)contex{ NSLog(@"in observeValueForKeyPath"); if ([keyPath isEqualToString:@"canGoBack"]) { BOOL canGoBack = [[change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1]]; if (canGoBack) { [backBtn setEnabled:YES]; }else{ [backBtn setEnabled:NO]; } }else{ BOOL canGoForward = [[change objectForKey:NSKeyValueChangeNewKey] isEqualToNumber:[NSNumber numberWithInt:1]]; if (canGoForward) { [forwardBtn setEnabled:YES]; }else{ [forwardBtn setEnabled:NO]; } } } -(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; //通过监听web view是否能够向前 或 向后来决定按钮是否可用,以前做自定义相机的时候能用这种方式监听是否在自动对焦,然后作出相应的处理, //但现在不管怎么试都没用,报错显示不能这样做,也不知为什么。。。 [webView addObserver:self forKeyPath:@"canGoBack" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; [webView addObserver:self forKeyPath:@"canGoForward" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; webView.delegate = self; [webView loadRequest:currentRequest]; } -(void)viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; if (webView.loading) { [webView stopLoading]; } webView.delegate = nil; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma makr -- button event action -(void)goBack:(id)sender{ NSLog(@"in goBack"); if (webView.loading) { [webView stopLoading]; } [webView goBack]; } -(void)refresh:(id)sender{ NSLog(@"in refresh"); if (webView.loading) { [webView stopLoading]; } //发生错误时则重新加载主页 if (hasError) { [webView loadRequest:currentRequest]; }else{ [webView reload]; } } -(void)goForward:(id)sender{ NSLog(@"in goForward"); if (webView.loading) { [webView stopLoading]; } [webView goForward]; } #pragma mark -- UIWebDelegate - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ return YES; } // 当UIWevView开始加载内容时调用 - (void)webViewDidStartLoad:(UIWebView *)webView{ NSLog(@"in webViewDidStartLoad"); [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; } // 当UIWevView完成内容加载时调用 - (void)webViewDidFinishLoad:(UIWebView *)webView{ NSLog(@"in webViewDidFinishLoad"); [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; //下面是测试 web view和js交互的例子 //该方法是把你传进来的 js 代码传入web网页中,然后返回执行的结果,返回null则为执行失败 NSString *title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"]; NSLog(@"title = %@",title); //下面是网上大牛写的,嵌入一个值的,是要针对指定网页的 [webView stringByEvaluatingJavaScriptFromString:@"var script = document.createElement('script');" "script.type = 'text/javascript';" "script.text = \"function myFunction() { " "var field = document.getElementsByName('q')[0];" "field.value='朱祁林';" "document.forms[0].submit();" "}\";" "document.getElementsByTagName('head')[0].appendChild(script);"]; [webView stringByEvaluatingJavaScriptFromString:@"myFunction();"]; } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{ NSLog(@"in didFailLoadWithError"); [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; [webView loadHTMLString:[NSString stringWithFormat:@"<html><center><font size=+5 color='red'>An error occurred:<br>%@</font></center></html>",[error localizedDescription]] baseURL:nil]; hasError = YES; } @end