iPadアプリで更新情報ページへアクセスするための内臓ブラウザを使っているんですが、iOSのUIActivityIndicator(下の画像)を使うことに嫌気がさしてしまいました。
というのも、iPhone4の頃からずっと見てきてさすがに飽きましたし、
読み込み状況と関係なく回り続けているだけなので、読み込みがちゃんと進んでいるのか不安になることがあるんです。
かといって定番のHUDは組み込むのが面倒で面白みもなかったので、思いつく限りで何か簡単なものを自作することにしました。
動画
WindowsのModern UIプログレスに似ています。
特徴について
主な特徴は以下。
・左上の大きな●は従来通り、読み込み処理実行中を表現
・中央の上から落ちてくるものがいわゆる「プログレスバー」的なもの
・上から下へ落ちるアニメーションによってデータ受信そのものを表現
・プログレスの到達点なるものはないが、同じページは落ちる数に大差ないので、「あとどれくらいで完了か」がなんとなくわかってくる
・実装が難しくない
左上のインジケータはもともと使うつもりではなかったんですが、プログレスが意外とすぐに落ちてこないため併用することにしました。
当初はインジケータを中央に表示し、プログレスが来たら隠すようにしていましたが、通信状況によってプログレスの間隔に間が空くので左上で常に表示させておくことに。
実装はこれからご紹介しますが、実装レベルの割りになかなかイケてるものができたと個人的に満足しています。
実装
まずはドロップアニメーションから。
webViewDidFinishLoad()が呼ばれるたびにドロップアニメーションを実行しているだけです。
UIWebViewデリゲートメソッドの
webViewDidFinishLoad(webView: UIWebView)
内で以下を実装すればokです。if webView.loading { // trueであれば読み込み中 let dropProgress = UILabel() dropProgress.frame = CGRectMake(0, -50, 30, 30) dropProgress.setCenterX(webView.width() / 2) dropProgress.text = "●" dropProgress.textAlignment = .Center dropProgress.font = .systemFontOfSize(25) dropProgress.textColor = UIColor.blueColor() dropProgress.backgroundColor = UIColor.clearColor() webView.addSubview(dropProgress) UIView.animateWithDuration(0.6, delay: 0, options: .CurveEaseOut, animations: { dropProgress.frame.origin.y = webView.height() }, completion: { value in dropProgress.removeFromSuperview() }) return } //// 読み込み完了でここを通るのでアルファインジケータの後始末をする _stopIndicator = true
●の描画はしたくなかったのでUILabelにこれ→●をセット。
そしてアニメーションでwebViewのheightを
dropIndicator.frame.origin.y
へセットすればちゃんと隠れます。このときEaseOutオプションにしておくと減速効果が素敵に映ります。
続いてアルファアニメーションのループメソッド。
var _stopIndicator = false func alphaAnimation(alpha: CGFloat, setAlpha: (a: CGFloat) -> Void) { UIView.animateWithDuration(0.8, delay: 0, options: .CurveEaseInOut, animations: { setAlpha(a: alpha) }, completion: { value in if _stopIndicator { // trueならalphaゼロにしてループ終了 UIView.animateWithDuration(0.8, delay: 0, options: .CurveEaseInOut, animations: { setAlpha(a: 0) }, completion: { value in }) return } let nextAlpha: CGFloat = alpha == 1.0 ? 0.0 : 1.0 //現在のalphaから判定 alphaAnimation(nextAlpha, setAlpha: { (a: CGFloat) in setAlpha(a: a) }) }) }
クロージャ使ってますし、ループするので循環参照に注意が必要です。(そしてもっとマシなアルゴリズムあるかも)
EaseInOutオプションとduration0.8の組み合わせにより、ホワーンホワーンというホタルの光(またはWindowsのCortana)のようなアニメーションを実現できます。
このメソッドをインジケータ作成後、alphaゼロを引数に呼び出します。
let indicator = UILabel() indicator.frame = CGRectMake(10, 10, 60, 60) indicator.text = "●" indicator.textColor = UIColor.blueColor() indicator.textAlignment = .Center indicator.font = .systemFontOfSize(90) indicator.backgroundColor = clearColor webview.addSubview(indicator) alphaAnimation(0.0, setAlpha: { (a: CGFloat) in indicator.alpha = a })
以上、自作インジケータでした。