[swift]挫折しながら覚えるiOS開発その9 WebViewのカスタマイズ


[まとめ] 現在開催中のKindleセール情報はこちら

前回はWebViewを使って記事のURLを表示する詳細ページの大枠ができました。

今回は、詳細ページのWebViewに戻るボタン、進むボタン、リロードボタン、シェアボタンを追加したいと思います。

また、Navigation Controllerの戻るボタンの色を変える対応もしたいと思います。

1. WebViewにボタン追加

LinkDetailViewControllerのStoryboard上に、「Toolbar」を追加し、その上に「Bar Button Item」と「Flexible Space Bar Button」をそれぞれ設置します。

今回は、戻るボタン、空白、進むボタン、空白、リロードボタン、空白、シェアボタンとなるように配置しました。

swift9-1

ViewControllerへの接続に関しては、以下のように6つの接続を追加しました。

機能 connection name type
戻るボタン Outlet backBtn UIBarButtonItem
進むボタン Outlet nextBtn UIBarButtonItem
戻るボタンを押した際のAction Action backPage UIBarButtonItem
進むボタンを押した際のAction Action nextPage UIBarButtonItem
リロードボタンを押した際のAction Action reloadPage UIBarButtonItem
シェアボタンを押した際のAction Action didTouchShareButton UIBarButtonItem

swift9-2

戻るボタン、進むボタンはブラウザの状況に応じてボタンの有効/無効を判定する必要があるため、Outletも定義しています。

続いて、Actionの内容をそれぞれ実装していきます。

シェアボタン以外はWebViewのメソッドを呼び出すだけで対応できます。

# LinkDetailViewController.swift

import UIKit

class LinkDetailViewController: BaseViewController, UIWebViewDelegate {

    @IBOutlet weak var webView: UIWebView!
    @IBOutlet weak var backBtn: UIBarButtonItem!
    @IBOutlet weak var nextBtn: UIBarButtonItem!

    var link: Link?

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.delegate = self

        self.canDisplayBannerAds = false

        // Do any additional setup after loading the view.
        if let link = self.link {
            initWithLink(link)
        }

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // 前へ
    @IBAction func backPage(sender: UIBarButtonItem) {
        self.webView.goBack()
    }

    // 次へ
    @IBAction func nextPage(sender: UIBarButtonItem) {
        self.webView.goForward()
    }

    // リロード機能
    @IBAction func reloadPage(sender: UIBarButtonItem) {
        self.webView.reload()
    }

    // シェア機能
    @IBAction func didTouchShareButton(sender: UIBarButtonItem) {
        // 共有する項目
        let activityItems = [
            link!.title,
            NSURL(string: link!.url)!
        ]
        // 除外するActivity
        let excludedActivityTypes = [
            UIActivityTypePrint,
            UIActivityTypeAssignToContact,
            UIActivityTypeSaveToCameraRoll,
            UIActivityTypeAirDrop,
            UIActivityTypeMail,
            UIActivityTypeMessage
        ]
        let activityVC = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        activityVC.excludedActivityTypes = excludedActivityTypes

        // ipad向けの設定
        if let presenter = activityVC.popoverPresentationController {
            presenter.barButtonItem = sender
        }

        self.presentViewController(activityVC, animated: true, completion: nil)
    }

    func initWithLink(link: Link) {
        self.loadRequest(link.url)
    }

    // MARK: - private
    func loadRequest(urlString: String) {
        let queryUrl = NSURL(string: urlString)
        let req = NSURLRequest(URL: queryUrl!)
        webView.loadRequest(req)
    }

    // 読み込み開始時に呼ばれる
    func webViewDidStartLoad(webView: UIWebView) {
        // ステータスバーのインジケーターを表示
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    }

    // 読み込み完了時に呼ばれる
    func webViewDidFinishLoad(webView: UIWebView) {
        // インジケータを非表示にする
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false

        // 戻る、進むボタンの有効性チェック
        self.backBtn.enabled = self.webView.canGoBack
        self.nextBtn.enabled = self.webView.canGoForward
    }
}

シェア部分で使っているUIActivityViewControllerに関してはQiitaのまとめ記事や、前回お伝えした参考書籍に詳しく書かれています。

[Swift]UIActivityの使い方まとめ – Qiita

一つ注意なのが、iPad対応の場合、以下のようにpopoverPresentationControllerの指定を行わないとiPadがクラッシュします。

        // ipad向けの設定
        if let presenter = activityVC.popoverPresentationController {
            presenter.barButtonItem = sender
        }

iPadのクラッシュに関しては以下の記事で詳しくまとめてくださっています。

iOS8の自爆機能について(笑)

これでWebViewにボタンを色々追加できました。

swift9-3

シェア画面も追加できています。

swift9-4

2. NavigationControllerのカスタマイズ

続いてはNavigationControllerのカスタマイズをします。

やりたいこととしては、以下のように戻るボタン(< Master)の<の色を変更し、Masterの文字をなくしたいです。

また、ヘッダーのタイトルとなっているDetailの表示も画像に置き換えたいです。

swift9-5

これを実現するためにUINavigationControllerを継承したNavigationController.swiftを追加します。

Storyboard上のNavigationControllerのCustomClassも、デフォルトのクラスからNavigationControllerに変更します。

# NavigationController.swift

import UIKit

class NavigationController: UINavigationController, UINavigationControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.delegate = self
    }

    override func viewDidAppear(animated: Bool) {
        // 戻るボタンの色を変更
        self.navigationBar.tintColor = UIColor(red:119.0/255, green:185.0/255, blue:66.0/255, alpha:1.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: UINavigationControllerDelegate
    func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
        let backButton: UIBarButtonItem = UIBarButtonItem()
        // 戻るボタンの文字を空文字にする
        backButton.title = ""
        viewController.navigationItem.backBarButtonItem = backButton
    }
}

これで戻るボタンの色変更と、戻る際の文字を非表示にすることができました。

ヘッダーの画像表示に関しては、以下のように各ControllerのviewDidLoadでnavigationItem.titleViewを設定する必要がありました。

let image = UIImage(named: "header_logo_green@2x.png")
self.navigationItem.titleView = UIImageView(image: image)

同じ記述を各Controllerに書いてしまうのはメンテナンス性が下がるのでできれば一箇所にまとめたいです。

そこで、各ViewControlerの継承元となるBaseViewController.swiftを追加します。

そして、BaseViewControllerのviewDidLoadにヘッダー画像表示処理を記述します。

# BaseViewController.swift

import UIKit

class BaseViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        let image = UIImage(named: "header_logo_green@2x.png")
        self.navigationItem.titleView = UIImageView(image: image)
    }
}

MasterTableViewControllerの継承元をBaseViewControllerに変更します(TableViewControllerからMasterTableViewControllerにリネームしました)。

# MasterTableViewController.swift
class MasterTableViewController: BaseViewController, UITableViewDataSource, UITableViewDelegate {

}

また、LinkDetailViewControllerもBaseViewControllerを継承するようにします。

# LinkDetailViewController.swift
class LinkDetailViewController: BaseViewController, UIWebViewDelegate {

}

シミュレータを起動するとナビゲーションの文字とヘッダーがカスタマイズできているのを確認できます。

swift9-3

これでWebViewを使った詳細ページのカスタマイズができました。

次回は再びTableViewに戻り、引っ張ってリロードを行うUIRefreshControlの対応を行いたいと思います。

参考

[まとめ] 現在開催中のKindleセール情報はこちら