質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • Swift 2

    1334questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。

swift2.xでWKWebViewにプログレスバーを付けたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,099

質問させてください。swift2.xでのストーリーボードを使わないWKWebViewの実装についてです。

現在、1ページだけの起動後に表示される画面に特定のwebページが表示させるだけのサンプルアプリをつくっています。WKWebViewのtitle、loading、estimatedProgressを監視対象に入れプログレスバーを設置する設定をしているのですが、どうやってもプログレスバーが表示されずに困っており3日ほど詰まってしまって前に進めない状況なのでなんとか解決できないかと思い、質問させていただきました。titleの設定やスワイプで前の画面に戻る動作、プログレスの値(0.0-1.0)を取得してコンソールに出力させるまではだいたい理解して実装ができています。

viewDidLoadの // プログレスバーを設定する あたりが間違っているのかなと思いいろいろ試しているのですがどうやってもプログレスバーが出てきません。

また、監視対象の解除について、 viewWillDisappear で解除すべきか deinit で解除すべきかで迷っております。こちらについてもお詳しい方がおられましたら教えていただけますととても嬉しいです。どうかよろしくお願いいたします。

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate {

    var webkitview: WKWebView?
    var progressView: UIProgressView!

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

        // ヘッダーにタイトルを設定する
        self.navigationItem.title = "Home"

        // WebKitのインスタンスをつくる
        self.webkitview = WKWebView()

        // WebKitをviewに紐付ける
        self.view = self.webkitview!

        // 表示する内容を設定する
        let url = NSURL(string: "https://www.nintendo.co.jp")
        let req = NSURLRequest(URL: url!)
        self.webkitview!.loadRequest(req)

        // スワイプで戻る動作を設定する
        self.webkitview!.allowsBackForwardNavigationGestures = true

        // プログレスバーを設定する
        self.webkitview!.navigationDelegate = self
        progressView = UIProgressView(frame: CGRectMake(0, self.navigationController!.navigationBar.frame.size.height, self.view.frame.size.width, 10))
        progressView.progressTintColor = UIColor.greenColor()
        progressView.trackTintColor = UIColor.whiteColor()
        progressView.layer.position = CGPoint(x:0, y:(self.navigationController?.navigationBar.frame.size.height)!)
        progressView.transform = CGAffineTransformMakeScale(1.0, 2.0)
        self.navigationItem.titleView?.addSubview(progressView)
    }

    deinit {
        // 監視対象を解除する
        webkitview!.removeObserver(self, forKeyPath: "estimatedProgress")
        webkitview!.removeObserver(self, forKeyPath: "loading")
        webkitview!.removeObserver(self, forKeyPath: "title")
    }

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

    override func viewWillAppear(animated: Bool) {
        // 監視対象を登録する
        self.webkitview!.addObserver(self, forKeyPath: "estimatedProgress", options: .New, context: nil)
        self.webkitview!.addObserver(self, forKeyPath: "loading", options: .New, context: nil)
        self.webkitview!.addObserver(self, forKeyPath: "title", options: .New, context: nil)
    }

    override func viewWillDisappear(animated: Bool) {
        // 監視対象を解除する
        self.webkitview!.removeObserver(self, forKeyPath: "estimatedProgress")
        self.webkitview!.removeObserver(self, forKeyPath: "loading")
        self.webkitview!.removeObserver(self, forKeyPath: "title")
    }

    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        if(keyPath == "estimatedProgress") {
            let progress : Float = Float(webkitview!.estimatedProgress)
            if(progressView != nil) {
                if(progress < 1.0) {
                    // プログレスバーを更新する
                    print("loaded:\(progress)")
                    progressView.setProgress(progress, animated: true)
                    UIApplication.sharedApplication().networkActivityIndicatorVisible = true
                } else {
                    // 読み込みが完了したらプログレスバーを消す
                    print("loaded:done")
                    progressView.setProgress(0.0, animated: false)
                    UIApplication.sharedApplication().networkActivityIndicatorVisible = false
                }
            }
        } else if(keyPath == "title") {
            // タイトルにページのタイトルを設定する
            let title = self.webkitview!.title
            self.navigationItem.title = title
        }
    }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

self.navigationItem.titleView?.addSubview(progressView)

ではなく、

self.navigationItem.titleView = progressView

で。(printすればわかりますが、self.navigationItem.titleViewはnilです)

解除についてはよくわからないのでパス。

【追記】

aoshima.natsukiさんのやりたいことを想像すると、viewDidLoadでprogressViewをセットするのではなく、読み込み開始時に、

self.navigationItem.titleView = progressView

読み込み終了時に、

self.navigationItem.titleView = nil

とすればいいと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/02 16:14 編集

    さっそくのご回答ありがとうございます。おっしゃる通りご呈示いただいたコードでほとんど思い通りのことが実現できました。また、追記でご指摘いただいた点についても納得しました。確かにこちらで指定すべきでした。ご丁寧にありがとうございます。

    ただこちらですと、self.navigationItem.title に指定していたページのタイトルが打ち消されてしまうのですが回避策はありますか?

    また、また、progressViewのサイズと位置の指定で、もしご存知であれば教えていただきたいのですが

    progressView = UIProgressView(frame: CGRectMake(0, self.navigationController!.navigationBar.frame.size.height, self.view.frame.size.width, 10))



    progressView.layer.position = CGPoint(x:0, y:(self.navigationController?.navigationBar.frame.size.height)!)

    がどうやら適応されないようです。記述の仕方は間違っていないと思っていたのですが、どこか悪い点は見受けられますでしょうか。試しにすべて0に指定しても何も変化がなく、幅が95%くらいから変わらず、位置も0にしても中途半端なところから動かず困っております。もしご存知であればこちらについても教えていただけますととても嬉しいです。

    キャンセル

  • 2016/05/02 16:45 編集

    読み込み中はタイトルの代わりにプログレスを表示するのかと思ったのですが、そういうわけではないんですね。何を実現したいのか(どうなったら正解なのか)を書いてもらわないとアドバイスのしようがありません。

    キャンセル

  • 2016/05/02 17:39

    言葉不足ですみません。読み込み中からnavigationbarにタイトルが表示させ、それとは別に読み込み率をnavigationbarの下に表示させたいです。このような見せ方をするのはあまり一般的ではないのでしょうか?よろしくお願いいたします。

    キャンセル

  • 2016/05/02 18:40 編集

    時間切れなので分かったことだけ書いておきます。

    ・WkWebViewの初期化
    現在、frame指定をしていないのでサイズが0になっています。ということは、progressViewの横幅も0になっているということです。
    → self.webkitview = WKWebView(frame: self.view.frame)

    ・addSubView
    progressViewはtitleViewにセットするのではなく、self.viewにセットして下さい。
    → self.view.addSubview(progressView)

    ・progressViewのY座標
    直値で100を指定してみて下さい。上記の横幅の件と合わせて、とりあえず画面に表示されると思います。
    navigationBarの高さでダメな理由は突き止められませんでした。
    あと、普通layer.positionは使わないと思うのですが何か意図があるのでしょうか?特に理由がなければframeで指定した方が良いと思います。

    では良いGWを!w

    キャンセル

  • 2016/05/02 19:19

    Y座標の件、ステータスバーの分だけ下げてやればいいかも知れません。http://qiita.com/to4iki/items/51c1b629c2d1884bbeb3

    それよりも、topLayoutGuideを取得出来るようであれば、これを使った方がいいです。
    http://poormemory.seesaa.net/s/article/409079244.html

    キャンセル

  • 2016/05/02 19:46 編集

    ご回答ありがとうございます。

    frame指定をしていないとサイズが0になってしまうのですね。知りませんでした。。frame指定をすることで self.view!.bounds.size.width が取得できるようになり幅100%でプログレスバーを設置することができるようになりました。

    pregressViewのY座標については self.navigationController?.navigationBar.frame.size.height がなぜか取得でき直接値で指定したとこをひとまず思い通りの位置に設置することができました。
    (追記:追記いただいた記事がとても参考になりそうです!ひとまず直接指定してしまいましたが後ほどこちらの方法で実現できないか試してみます!)

    その他もろもろの良くなかった書き方を修正し、思い描いていたものが実現できました。ご丁寧にありがとうございました。良いGWをお過ごし下さい!

    キャンセル

関連した質問

同じタグがついた質問を見る

  • Swift 2

    1334questions

    Swift 2は、Apple社が独自に開発を行っている言語「Swift」のアップグレード版です。iOSやOS X、さらにLinuxにも対応可能です。また、throws-catchベースのエラーハンドリングが追加されています。