Posted on

UIWebView練習作業

作業目標:http://www.youtube.com/watch?v=azplcMbuoQ4&feature=youtu.be
練習檔案:homework0831

先介紹一下UIWebView

UIWebView的資料來源主要有三者:

  1. 本機上的HTML字串
  2. 本機上的資料 + MIME type
  3. 遠端的URL

這邊有中文的介紹:http://www.inside.com.tw/2010/03/14/cs193p-lecture-12

作業練習開始

首先我先拉出storyboard
螢幕快照 2013-09-04 下午11.30.34

然後我練習使用程式去產生UINavigationController,這是在AppDelegate.m裡

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

UINavigationController * navi = [UINavigationController new];
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
UIViewController * controller = [storyboard instantiateViewControllerWithIdentifier:@"pink"];
[navi pushViewController:controller animated:YES];
self.window.rootViewController = navi;
return YES;
}

然後ViewController.h裡在viewDidLoad時初始化一些頁面數值

- (void)viewDidLoad
{
[super viewDidLoad];
[self.inputURL setAdjustsFontSizeToFitWidth:YES];//設定下方網址列的大小會自動resize
self.title = @"填入網址";
self.inputURL.text = @"http://www.apple.com";
}

實作按鈕按下時的動作

- (IBAction)goWeb:(id)sender {
//取出webview的view
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
WebViewController * webView = [storyboard instantiateViewControllerWithIdentifier:@"webView"];
webView.urlString = self.inputURL.text;
webView.delegate = self;
[self.inputURL resignFirstResponder];//收起鍵盤
[self.navigationController pushViewController:webView animated:YES];
}

接下來做WebViewController.m裡的內容,
在這邊我弄了一個下載進度的物件叫作UIActivityIndicatorView
這部份首先要先在- (void)viewDidLoad裡初始化載入效果

//加入載入特效
aciv = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; colorView=[[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];

[colorView setBackgroundColor:[UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:0.4]];

然後加上下面兩段程式碼

//載入特效
- (void)addLoading{
aciv.activityIndicatorViewStyle=UIActivityIndicatorViewStyleWhite; aciv.center=CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2-10);
[self.view addSubview:colorView];
[aciv startAnimating];
[self.view addSubview:aciv];
}

- (void)removeLoading{
[colorView removeFromSuperview];
[aciv stopAnimating];
[aciv removeFromSuperview];
}

然後在實做UIWebView的Delegate去設定載入畫面
[UIApplication sharedApplication].networkActivityIndicatorVisible這個是在上方指示列的圈圈圖示

- (void)webViewDidStartLoad:(UIWebView *)webView
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self addLoading];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self removeLoading];
}

遇到問題(高手幫忙看3Q)

然後其實接下來這一點問題我弄了非常久~ 就是,在從上一頁傳來網址時,
也會執行到
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
所以會必須去判斷現在是使用者點擊的link,或是是從上頁傳來的指令

為了這個需求,我用了幾個方式,但都有問題,包括現在的其實也有,但因為實在搞太久~
所以就先這樣@@等老師公布他的作法後再來補修正

我總用試了這些方式

  1. 使用一個BOOL去判別,只有第一次loading頁面時不做跳頁呼叫,然後當webViewDidFinishLoad時將BOOL改為NO
    問題點:有某些頁面會有js檔案,當頁面全部載入完成後,執行js後,就又會再第二次讀取網路資料,此時頁面就會莫名的突然回到第一頁然後顯示網址。(例如:我的部落格http://claire-chang.com)
  2. 使用NSConnection(http://stackoverflow.com/questions/9475768/loading-nsdata-into-a-uiwebview)
    這是一個異想天開(?)的想法,我想說,第一次loading時用NSConnection去讀html,然後用loadHTMLString:baseURL:來顯示在畫面上。結果html成功的載下來了,但是不知為何WebView呈現一片空白。
    在網路上查了一下,似乎是因為<scripe>標籤的關係(不確定)
  3. 現在版本的方式:偵測使用者點擊事件,當使用者點擊時,判斷現在是使用者點擊事件,下一次的網頁讀取便會跳頁。
    不過這種方式也有問題,同第一點,不過狀況會變成若頁面尚未載入完,使用者就點擊非link的地方時,js呼叫讀取網頁時,就會跳回第一頁,然後網址顯示為js呼叫的頁面網址= =

也是因為這樣子,我才會去製作下載畫面,想說在未loading完前不讓使用者按下WebView,
結果因為畫面會先loading完成、然後才自動因js而去呼叫另一個網址。
中間還是會有使用者可以點擊畫面的時間點。

我總覺得UIWebView應該有個東西是可以直接判別是否是使用者呼叫的,
觀察過dataDetectorTypes的值,卻似乎不是~orz
有知道的人麻煩幫解惑吧~3Q!
ps:若想試有js會在loading完成後再次loading的狀況,請把網址設為我的部落格http://claire-chang.com

因為我是用第三種方式,所以我對WebView增加了碰觸事件的偵聽
首先在- (void)viewDidLoad設定碰觸事件監聽

//設定碰觸事件
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleTapFrom:)];
longPress.minimumPressDuration = .001;
longPress.delegate = self;
[self.web addGestureRecognizer:longPress];
[self.web addGestureRecognizer:test];

然後要實作UIGestureRecognizerDelegate

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

上面這個一定要加,這樣子handleTapFrom:才會被呼叫到
然後當按到時將bool值改成YES

-(void)handleTapFrom :(UITapGestureRecognizer *)sender{
    NSLog(@"handleTapFrom:%d",sender.state);
    isClick = YES;
}

當讀取網頁且isClick是YES時就跳回第一頁

-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
    if(isClick){
        [self.delegate userClickWebLink:request.URL.absoluteString];
        return NO;
    }
    return YES;
}

這時再回去ViewController.m增加接收的方法

-(void) userClickWebLink: (NSString *) url{
    [self.navigationController popViewControllerAnimated:YES];
    self.title = @"點選網址";
    self.webUrl.text = url;
}