LoginSignup
7
6

More than 5 years have passed since last update.

PageMenuを使ってキュレーションアプリを作る(その2)【Swift3.0】

Last updated at Posted at 2016-12-16

キュレーションアプリを作る(その2)

横スライドのタブメニューライブラリPageMenuを使ったキュレーションアプリの実装手順を2回に分けて紹介します。本記事はその2回めです。今回はブラウズ機能を追加します。

その1はこちら

1.ビューコントローラーとセグエの追加

起動時の各Webビュー内でブラウズできるようにしてもよいのですが、今回はブラウズ用のビューコントローラーを追加することにしましたので、そこに遷移するためのセグエも追加します。
2-1.png

2.セグエの設定

セグエのidentifierを設定します。今回はbrowseにしました。
2-2.png

3.ブラウズ用クラスの追加

ブラウズ用のクラスを作成します。メニュー:File → New → Fileと辿り、「Cocoa Touch Class」をダブルクリック、UIViewControllerをサブクラスに選択します。今回はBrowseViewControllerという名前にしました。
2-3.png

4.ストーリーボード上のViewControllerと紐付け

ストーリーボード上のブラウズ用のビューコントローラーにBrowseViewControllerを割り当てます。
2-4.png

5.ブラウズクラスの実装

実装に伴い、BackArrowという戻るボタンのイメージセットを用意します。
イメージセットの作成にはココを参考にしてください。

BrowseViewController.swif

// Swift3.0

import UIKit

class BrowseViewController: UIViewController,UIWebViewDelegate {

    // 別ビューから受け取るリクエスト
    var request:URLRequest!

    // ウェブビュー
    var webView:UIWebView!

    // 「戻る」ボタンを配置するツールバー
    var toolbar:UIToolbar?

    override func viewDidLoad() {
        super.viewDidLoad()

        // ウェブビューを画面いっぱいに作成
        webView = UIWebView(frame: self.view.bounds)
        webView.delegate = self

        // URLリクエスト
        let req = URLRequest(url:request.url!)
        // ウェブビューにロード
        webView.loadRequest(req)
        // ウェブビューを表示
        self.view.addSubview(webView)

        // 「ホームへ戻る」ボタンの作成
        let button = UIButton(frame: CGRect(x:0,y:(self.view.bounds.height-40),width:self.view.bounds.width,height:40))
        button.titleLabel?.font = UIFont.systemFont(ofSize: 14)
        button.setTitle("ホームへ戻る", for: .normal)
        button.setTitleColor(UIColor.white, for: .normal)
        button.backgroundColor = UIColor.lightGray
        button.addTarget(self, action: #selector(homeBack), for: .touchUpInside)
        self.view.addSubview(button)

    }

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

    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {

        if navigationType == UIWebViewNavigationType.linkClicked {

            // ToolBarの制御
            if toolbar == nil {
                toolbar = UIToolbar(frame: CGRect(x:0,y:0,width:self.view.bounds.width,height:70))

                // Bar Button Item
                let img = UIImage(named:"BackArrow")!.withRenderingMode(UIImageRenderingMode.alwaysOriginal)
                let item = UIBarButtonItem(image: img,
                                           style: UIBarButtonItemStyle.plain,
                                           target: nil,
                                           action: #selector(BrowseViewController.backBrowse))
                let items = [item]
                toolbar?.items = items

                self.view.addSubview(toolbar!)
            }
        }

        return true
    }

    func webViewDidFinishLoad(_ webView: UIWebView) {

        if webView.isLoading {
            return
        }

        toolbar?.isHidden = true

        // 戻るボタン
        if self.webView.canGoBack {
            toolbar?.isHidden = false
        } else {
            toolbar?.isHidden = true
        }
    }

    func backBrowse(){
        self.webView.goBack()
    }

    func homeBack() {
        self.dismiss(animated: true, completion: nil)
    }

}

6.ContentsViewControllerとViewControllerの改修

その1で作成済みのContentsViewController.swiftに以下を追加します。masterViewPointerはContentsViewControllerからViewController上のセグエを実行可能にするためのものです(protocol不要のデリゲートパタンのようなもの)。func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> BoolはリクエストをフックするUIWebviewのデリゲートメソッドです。リクエストをフックしてリンククリックであれば、ViewContoroller上のbrowseメソッドを実行し、そのリクエストをキャンセル(return false)します。

  var masterViewPointer:ViewController?
  func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        if navigationType == UIWebViewNavigationType.linkClicked {
            masterViewPointer?.browse(request)
           return false
  }

追加後のContentsViewController.swift

import UIKit

class ContentsViewController: UIViewController ,UIWebViewDelegate{

    var webView:UIWebView!
    var siteUrl:String!

    var masterViewPointer:ViewController?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

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


    // MARK: Webview delegate
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {

        if navigationType == UIWebViewNavigationType.linkClicked {
            masterViewPointer?.browse(request)
            return false
        }

        return true
    }
}

さらに、その1で作成したViewController.swiftに以下を追加します。ContentsViewControllerで発生したリクエストをViewControllerで受け取るための追加です。

var request:URLRequest?
controller.masterViewPointer = self
    func browse(_ request:URLRequest) {
        self.request = request
        performSegue(withIdentifier: "browse", sender: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "browse" {
            let vc = segue.destination as! BrowseViewController
            vc.request = self.request
        }
    }

追加後のViewController.swift

import UIKit

class ViewController: UIViewController {

    // インスタンス配列
    var controllerArray : [UIViewController] = []
    var pageMenu : CAPSPageMenu?

    var request:URLRequest?

    // サイト情報
    let siteInfo:[Dictionary<String,String>] = [
        ["title":"ヤフー!知恵袋","url":"http://chiebukuro.yahoo.co.jp/"],
        ["title":"教えて!goo","url":"http://oshiete.goo.ne.jp/"],
        ["title":"OKWAVE","url":"http://okwave.jp/"],
        ["title":"発言小町","url":"http://komachi.yomiuri.co.jp/"],
        ["title":"BIGLOBEなんでも相談室","url":"http://soudan.biglobe.ne.jp/sp/"]
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        for site in siteInfo {

            let controller:ContentsViewController = ContentsViewController(nibName: "ContentsViewController", bundle: nil)

            controller.masterViewPointer = self

            controller.title = site["title"]!
            controller.siteUrl = site["url"]!

            controller.webView = UIWebView(frame : self.view.bounds)
            controller.webView.delegate = controller
            controller.view.addSubview(controller.webView)
            let req = URLRequest(url: URL(string:controller.siteUrl!)!)
            controller.webView.loadRequest(req)
            controllerArray.append(controller)

        }

        // Customize menu (Optional)
        let parameters: [CAPSPageMenuOption] = [
            .scrollMenuBackgroundColor(UIColor.white),
            .viewBackgroundColor(UIColor.white),
            .bottomMenuHairlineColor(UIColor.blue),
            .selectionIndicatorColor(UIColor.red),
            .menuItemFont(UIFont(name: "HelveticaNeue", size: 14.0)!),
            .centerMenuItems(true),
            .menuItemWidthBasedOnTitleTextWidth(true),
            .menuMargin(16),
            .selectedMenuItemLabelColor(UIColor.black),
            .unselectedMenuItemLabelColor(UIColor.gray)

        ]

        // Initialize scroll menu

        let rect = CGRect(origin: CGPoint(x: 0,y :20), size: CGSize(width: self.view.frame.width, height: self.view.frame.height))
        pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: rect, pageMenuOptions: parameters)

        self.addChildViewController(pageMenu!)
        self.view.addSubview(pageMenu!.view)

        pageMenu!.didMove(toParentViewController: self)

    }

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

    func browse(_ request:URLRequest) {
        self.request = request
        performSegue(withIdentifier: "browse", sender: nil)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "browse" {
            let vc = segue.destination as! BrowseViewController
            vc.request = self.request
        }
    }
}

7.ビルドしてみる

起動後にロードされるウェブビュー内のリンクをクリックするとBrowseViewへ遷移し、そのBrowseViewが持つwebView内でリクエストが展開されます。
3-2.png

8.補足

今回、戻るボタン付きツールバーの表示・非表示は、UIWebViewNavigationType.linkClickedのみをフックして判定をおこなっています。フォームのポスト時などには対応していません。

参考:UIWebViewNavigationType

public enum UIWebViewNavigationType : Int {

    case linkClicked

    case formSubmitted

    case backForward

    case reload

    case formResubmitted

    case other
}

プロジェクト一式をGitHubに置いときます

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6