iOS - Swift で WebViewアプリを作ってみた

Swift WebView を使ってWebページを表示するだけのアプリを作ってみます。
初めて実装する人でもわかるよう、細かくコメント入れています。
是非、お試しください。

テンプレートは Single View Application にします。

Webページを表示する

UIWebViewクラスを使って WebView を実装していきます。
WebView を実装するには他にも WKWebView というクラスがあります。

class ViewController: UIViewController {
    
    var webView: UIWebView?
    
    var targetURL = "http://www.yahoo.co.jp/"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // WebViewを生成する
        self.webView = self.createWebView()
        
        // サブビューを追加する
        self.view.addSubview(self.webView!)
        
        // リクエストを生成する
        var url = NSURL(string: targetURL)
        var request = NSURLRequest(URL: url!)
        
        // 指定したページを読み込む
        self.webView?.loadRequest(request)
    }
    
    // WebView を生成する
    func createWebView() -> UIWebView {
        // UIWebViewのインスタンスを生成
        let _webView = UIWebView()
        
        // 全画面表示にする
        _webView.frame = self.view.bounds
        
        return _webView
    }

f:id:kzy52:20150218211310p:plain

ステータスバーとビューが被らないようにする

ステータスバーと追加したビューが被ってしまっているのでステータスバーの高さに合わせてビューのサイズを変更します。

class ViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // 横幅、高さ、ステータスバーの高さを取得する
        let width: CGFloat! = self.view.bounds.width
        let height: CGFloat! = self.view.bounds.height
        let statusBarHeight: CGFloat! = UIApplication.sharedApplication().statusBarFrame.height
        
        // WebViewを生成する
        self.webView = self.createWebView(frame: CGRectMake(0, statusBarHeight, width, height - statusBarHeight))
        ...
    }
    
    // WebView を生成する
    func createWebView(#frame: CGRect) -> UIWebView {
        // UIWebViewのインスタンスを生成
        let _webView = UIWebView()
        
        // 画面サイズを設定する
        _webView.frame = frame
        
        return _webView
    }
    ...
}

UIApplication.sharedApplication().statusBarFrame.height

これでステータスバーの高さを取得できます。

CGRectMake

対象オブジェクトのサイズと位置を指定したい場合に使用します。

CGRect rect = CGRectMake(位置x, 位置y, 幅, 高さ)

このように生成します。

f:id:kzy52:20150218212526p:plain

ランドスケープモード(横)で表示が崩れないようにする

class ViewController: UIViewController {
    ...

    func createWebView(#frame: CGRect) -> UIWebView {
        ...
        _webView.frame = frame
        
        // ビューサイズの自動調整
        _webView.autoresizingMask = UIViewAutoresizing.FlexibleRightMargin |
            UIViewAutoresizing.FlexibleTopMargin |
            UIViewAutoresizing.FlexibleLeftMargin |
            UIViewAutoresizing.FlexibleBottomMargin |
            UIViewAutoresizing.FlexibleWidth |
            UIViewAutoresizing.FlexibleHeight
        
        return _webView
    }

    // ビューが再レイアウトされるときに呼び出される
    override func viewWillLayoutSubviews() {
        let statusBarHeight: CGFloat! = UIApplication.sharedApplication().statusBarFrame.height
        self.webView?.frame = CGRectMake(0, statusBarHeight, self.view.bounds.width, self.view.bounds.height)
    }
}

autoresizingMask

子要素の自動調整をしてくれます。
値は以下を指定することができます。

設定値 説明
UIViewAutoresizingFlexibleTopMargin 上を自動調整
UIViewAutoresizingFlexibleBottomMargin 下を自動調整
UIViewAutoresizingFlexibleRightMargin 右を自動調整
UIViewAutoresizingFlexibleLeftMargin 左を自動調整
UIViewAutoresizingFlexibleWidth 幅を自動調整
UIViewAutoresizingFlexibleHeight 高さを自動調整
UIViewAutoresizingNone 自動調整なし

viewWillLayoutSubviews()

ビューが再レイアウトされるときに呼び出されます。
ランドスケープモードだとステータスバーの部分が空いてしまうので再度ビューのサイズを設定しています。

f:id:kzy52:20150218222531p:plain

インジケータを表示する

class ViewController: UIViewController, UIWebViewDelegate {
    ...
    override func viewDidLoad() {
        ...
        self.webView?.loadRequest(request)
        
        // インジケータを表示する
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    }
    
    // WebView を生成する
    func createWebView(#frame: CGRect) -> UIWebView {
        // UIWebViewのインスタンスを生成
        let _webView = UIWebView()
        
        // デリゲートを指定する
        _webView.delegate = self;
        ...
    }
    ...
    // WebView がコンテンツの読み込みを完了した後に呼ばれる
    func webViewDidFinishLoad(webView: UIWebView) {
        // インジケータを非表示にする
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    }
    ...
}

UIWebViewDelegate

ウェブコンテンツを読み込んだ時の処理を追加したいので UIWebViewDelegate プロトコルを追加します。
WebView がコンテンツの読み込みを開始した場合に呼ばれる webViewDidStartLoad と
完了した場合に呼ばれる webViewDidFinishLoad が使用できるようになります。

UIApplication.sharedApplication().networkActivityIndicatorVisible

ネットワークにアクセスしていることを示すインジケータの表示、非表示を設定することができます。

f:id:kzy52:20150218220334p:plain

戻る、進む、リフレッシュ、Safariで開くボタンを表示する

class ViewController: UIViewController, UIWebViewDelegate {
    ...    
    var toolBar: UIToolbar?
    var rewindButton = UIBarButtonItem()
    var fastForwardButton = UIBarButtonItem()
    var refreshButton = UIBarButtonItem()
    var openInSafari = UIBarButtonItem()

    override func viewDidLoad() {
        ...
        self.view.addSubview(self.webView!)
        
        // ツールバーを生成する
        self.toolBar = self.createToolBar(frame: CGRectMake(0, height-44, width, 40.0), position: CGPointMake(width/2, height-20.0))
        
        // サブビューを追加する
        self.view.addSubview(self.toolBar!)
        
        // リクエストを生成する
        ...
        
        // 前のページに戻れるかどうか
        self.rewindButton.enabled = self.webView!.canGoBack
        // 次のページに進めるかどうか
        self.fastForwardButton.enabled = self.webView!.canGoForward
        self.refreshButton.enabled = false
        self.openInSafari.enabled = false
    }
    ...
    
    // ツールバーを生成する
    func createToolBar(#frame: CGRect, position: CGPoint) -> UIToolbar {
        // UIWebViewのインスタンスを生成
        let _toolBar = UIToolbar()
        
        // ツールバーのサイズを決める.
        _toolBar.frame = frame
        
        // ツールバーの位置を決める.
        _toolBar.layer.position = position
        
        // 文字色を設定する
        _toolBar.tintColor = UIColor.blueColor()
        // 背景色を設定する
        _toolBar.backgroundColor = UIColor.whiteColor()
        
        // 各ボタンを生成する
        // UIBarButtonItem(style, デリゲートのターゲットを指定, ボタンが押されたときに呼ばれるメソッドを指定)
        let spacer: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
        self.rewindButton = UIBarButtonItem(barButtonSystemItem: .Rewind, target: self, action: "back:")
        self.fastForwardButton = UIBarButtonItem(barButtonSystemItem: .FastForward, target: self, action: "forward:")
        self.refreshButton = UIBarButtonItem(barButtonSystemItem: .Refresh, target: self, action: "refresh:")
        self.openInSafari = UIBarButtonItem(barButtonSystemItem: .Action, target: self, action: "safari:")
        
        // ボタンをツールバーに入れる.
        _toolBar.items = [rewindButton, fastForwardButton, refreshButton, spacer, openInSafari]
        
        return _toolBar
    }
    ...
    
    // WebViewがコンテンツの読み込みを開始した時に呼ばれる
    func webViewDidStartLoad(webView: UIWebView) {
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
        
        self.rewindButton.enabled = self.webView!.canGoBack
        self.fastForwardButton.enabled = self.webView!.canGoForward
        self.refreshButton.enabled = true
        self.openInSafari.enabled = true
    }
    
    // WebView がコンテンツの読み込みを完了した後に呼ばれる
    func webViewDidFinishLoad(webView: UIWebView) {
        // インジケータを非表示にする
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
        
        self.rewindButton.enabled = self.webView!.canGoBack
        self.fastForwardButton.enabled = self.webView!.canGoForward
    }
    
    // 戻るボタンの処理
    @IBAction func back(AnyObject) {
        self.webView?.goBack()
    }
    
    // 進むボタンの処理
    @IBAction func forward(AnyObject) {
        self.webView?.goForward()
    }
    
    // 再読み込みボタンの処理
    @IBAction func refresh(AnyObject) {
        self.webView?.reload()
    }
    
    // safari で開く
    @IBAction func safari(AnyObject) {
        let url = self.webView?.request?.URL
        UIApplication.sharedApplication().openURL(url!)
    }
    ...
}

CGPointMake

対象オブジェクトの位置を指定したい場合に使用します。

CGPoint point = CGPointMake(位置x, 位置y);

このように生成します。

@IBAction

クリックイベントの定義には IBAction を使用します。

f:id:kzy52:20150218221905p:plain

最終的には以下のようになります。

import UIKit

class ViewController: UIViewController, UIWebViewDelegate {
    
    var webView: UIWebView?
    
    var targetURL = "http://www.yahoo.co.jp/"
    
    var toolBar: UIToolbar?
    var rewindButton = UIBarButtonItem()
    var fastForwardButton = UIBarButtonItem()
    var refreshButton = UIBarButtonItem()
    var openInSafari = UIBarButtonItem()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // 横幅、高さ、ステータスバーの高さを取得する
        let width: CGFloat! = self.view.bounds.width
        let height: CGFloat! = self.view.bounds.height
        let statusBarHeight: CGFloat! = UIApplication.sharedApplication().statusBarFrame.height
        
        // WebViewを生成する
        self.webView = self.createWebView(frame: CGRectMake(0, statusBarHeight, width, height - statusBarHeight))
        
        // サブビューを追加する
        self.view.addSubview(self.webView!)
        
        // ツールバーを生成する
        self.toolBar = self.createToolBar(frame: CGRectMake(0, height-44, width, 40.0), position: CGPointMake(width/2, height-20.0))
        
        // サブビューを追加する
        self.view.addSubview(self.toolBar!)
        
        // リクエストを生成する
        var url = NSURL(string: targetURL)
        var request = NSURLRequest(URL: url!)
        
        // 指定したページを読み込む
        self.webView?.loadRequest(request)
        
        // インジケータを表示する
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
        
        // 前のページに戻れるかどうか
        self.rewindButton.enabled = self.webView!.canGoBack
        // 次のページに進めるかどうか
        self.fastForwardButton.enabled = self.webView!.canGoForward
        self.refreshButton.enabled = false
        self.openInSafari.enabled = false
    }
    
    // WebView を生成する
    func createWebView(#frame: CGRect) -> UIWebView {
        // UIWebViewのインスタンスを生成
        let _webView = UIWebView()
        
        // デリゲートを指定する
        _webView.delegate = self;
        
        // 画面サイズを設定する
        _webView.frame = frame
        
        // ビューサイズの自動調整
        _webView.autoresizingMask = UIViewAutoresizing.FlexibleRightMargin |
            UIViewAutoresizing.FlexibleTopMargin |
            UIViewAutoresizing.FlexibleLeftMargin |
            UIViewAutoresizing.FlexibleBottomMargin |
            UIViewAutoresizing.FlexibleWidth |
            UIViewAutoresizing.FlexibleHeight
        
        return _webView
    }
    
    // ツールバーを生成する
    func createToolBar(#frame: CGRect, position: CGPoint) -> UIToolbar {
        // UIWebViewのインスタンスを生成
        let _toolBar = UIToolbar()
        
        // ツールバーのサイズを決める.
        _toolBar.frame = frame
        
        // ツールバーの位置を決める.
        _toolBar.layer.position = position
        
        // 文字色を設定する
        _toolBar.tintColor = UIColor.blueColor()
        // 背景色を設定する
        _toolBar.backgroundColor = UIColor.whiteColor()
        
        // 各ボタンを生成する
        // UIBarButtonItem(style, デリゲートのターゲットを指定, ボタンが押されたときに呼ばれるメソッドを指定)
        let spacer: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil)
        self.rewindButton = UIBarButtonItem(barButtonSystemItem: .Rewind, target: self, action: "back:")
        self.fastForwardButton = UIBarButtonItem(barButtonSystemItem: .FastForward, target: self, action: "forward:")
        self.refreshButton = UIBarButtonItem(barButtonSystemItem: .Refresh, target: self, action: "refresh:")
        self.openInSafari = UIBarButtonItem(barButtonSystemItem: .Action, target: self, action: "safari:")
        
        // ボタンをツールバーに入れる.
        _toolBar.items = [rewindButton, fastForwardButton, refreshButton, spacer, openInSafari]
        
        return _toolBar
    }
    
    // ビューが再レイアウトされるときに呼び出される
    override func viewWillLayoutSubviews() {
        let statusBarHeight: CGFloat! = UIApplication.sharedApplication().statusBarFrame.height
        self.webView?.frame = CGRectMake(0, statusBarHeight, self.view.bounds.width, self.view.bounds.height)
    }
    
    // WebViewがコンテンツの読み込みを開始した時に呼ばれる
    func webViewDidStartLoad(webView: UIWebView) {
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
        
        self.rewindButton.enabled = self.webView!.canGoBack
        self.fastForwardButton.enabled = self.webView!.canGoForward
        self.refreshButton.enabled = true
        self.openInSafari.enabled = true
    }
    
    // WebView がコンテンツの読み込みを完了した後に呼ばれる
    func webViewDidFinishLoad(webView: UIWebView) {
        // インジケータを非表示にする
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
        
        self.rewindButton.enabled = self.webView!.canGoBack
        self.fastForwardButton.enabled = self.webView!.canGoForward
    }
    
    // 戻るボタンの処理
    @IBAction func back(AnyObject) {
        self.webView?.goBack()
    }
    
    // 進むボタンの処理
    @IBAction func forward(AnyObject) {
        self.webView?.goForward()
    }
    
    // 再読み込みボタンの処理
    @IBAction func refresh(AnyObject) {
        self.webView?.reload()
    }
    
    // safari で開く
    @IBAction func safari(AnyObject) {
        let url = self.webView?.request?.URL
        UIApplication.sharedApplication().openURL(url!)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

ソースコード

kzy52/ios-swift-webview-example · GitHub

参考

http://iphone-tora.sakura.ne.jp/uikit_size.html

http://blog.impl.co.jp/post/60930914933/ios-autoresizingmask