この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
データ取得や重い処理を行っている間、表示しなければならないぐるぐる回っている例のあれです。 表示中は操作させないようにしたり、できればかっこいいやつがよかったりと実は意外と面倒なんですよね。 でも無駄にソース書きたくないし、でも表示しないわけにはいかないし、手軽に使えてなんかかっこいいやつないかな、...あった!!
ってなわけで、たった数行でかっこいいローディングを表示するSVProgressHUDを紹介します。はまりどころもあるので、最後まで読んでいってください。
SVProgressHUDの特徴
SVProgressHUDの特徴として、
- 導入・使い方が簡単
- かゆいところに手が届く
- ARC対応
- MITライセンス
があげられます。とにもかくにも使ってみましょう。
早速使ってみよう
開発環境は以下の通り。
- Xcode 4.5.1
- iOS SDK 6.0
サンプルプロジェクトの作成
XCodeを開き、Single View Applicationを選択してプロジェクトを作成します。
プロジェクト名にSVProgressHUDSampleと入力し、Use StoryboardsとUse Automatic Reference Countingにチェックを入れてプロジェクトを作成し、任意の場所に保存します。
SVProgressHUDのダウンロード
SVProgressHUDはgithubからダウンロードできます。https://github.com/samvermette/SVProgressHUD
SVProgressHUDを導入
導入は超簡単です。まずgithubから取得したSVProgressHUDの中にある次の3つのファイルを自分のプロジェクトに追加します。
- SVProgressHUD/SVProgressHUD.bundle
- SVProgressHUD/SVProgressHUD.h
- SVProgressHUD/SVProgressHUD.m
そして自分のプロジェクトにQuartzCore.frameworkを追加します。
これでSVProgressHUDを使う準備が整いました。
使ってみる
今回はUIWebViewを配置し、ページを読み込み中の間、SVProgressHUDを表示するだけの簡単なサンプルプロジェクトを作成します。
MainStoryboard.storyboardにUIWebViewを配置して、プロパティに追加しておきましょう。名前はwebViewとしておきます。delegateにView Controllerを指定することをわすれずに!
ViewController.hを編集
今回のサンプルでは、読み込み開始と終了のタイミングで表示/非表示を切り替えたいので、UIWebViewDelegateを実装しましょう。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController <UIWebViewDelegate>
@property (weak, nonatomic) IBOutlet UIWebView *webView;
@end
ViewController.mを編集
#import "ViewController.h"
// 1.SVProgressHUDをインポート
#import "SVProgressHUD.h"
...
@implementation ViewController
...
// ビューが描画される前に呼ばれるメソッド
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// 「https://classmethod.jp/」の読み込みを開始する
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://classmethod.jp/"]];
[self.webView loadRequest:req];
}
// ページ読込開始直後に呼ばれるデリゲートメソッド
- (void)webViewDidStartLoad:(UIWebView *)webView
{
// 2.SVProgressHUDを表示する
[SVProgressHUD show];
}
// ページ読込終了直後に呼ばれるデリゲートメソッド
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// 3.SVProgressHUDを非表示にする
[SVProgressHUD dismiss];
}
...
@end
実際にSVProgressHUDに関係するのはたった3カ所!まず、ファイルの先頭でSVProgressHUD.hをインポートしてあげます(1)。そしてページ読込開始したら[SVProgressHUD show];でローディングを表示(2)し、読み込みが完了したら[SVProgressHUD dismiss];で非表示(3)にします。とても簡単ですね!
もっと使ってみる
表示するとき
- + (void)show;
- ローディングを表示する(メッセージなし)。
- + (void)showWithMaskType:(SVProgressHUDMaskType)maskType
- マスクタイプを指定してローディングを表示する(メッセージなし)。
- + (void)showWithStatus:(NSString*)string
- 表示するメッセージを指定してローディングを表示する。
- + (void)showWithStatus:(NSString*)string maskType:(SVProgressHUDMaskType)maskType
- 表示するメッセージとマスクタイプを指定してローディングを表示する。
超便利なマスクタイプ
個人的に便利なのがマスクタイプです。マスクタイプを指定するだけでユーザーの画面操作を有効/無効に設定できます。マスクタイプは以下の4つから指定できます。
- SVProgressHUDMaskTypeNone
- ユーザの画面操作を許可する。オーバーレイなし。デフォルトはこれ。
- SVProgressHUDMaskTypeClear
- ユーザの画面操作を許可しない。オーバーレイなし。
- SVProgressHUDMaskTypeBlack
- ユーザの画面操作を許可しない。背景黒、アルファ50%のオーバーレイを表示する。
- SVProgressHUDMaskTypeGradient
- ユーザの画面操作を許可しない。アラートビューを表示したときのようなオーバーレイを表示する。
非表示にするとき
- + (void)dismiss;
- ローディングを非表示にする。
- + (void)showSuccessWithStatus:(NSString*)string;
- ローディング中の処理が成功した旨を指定したメッセージとともに表示する。表示後1秒経過したら非表示になる。
- + (void)showErrorWithStatus:(NSString *)string;
- ローディング中の処理が失敗した旨を指定したメッセージとともに表示する。表示後1秒経過したら非表示になる。
- + (void)showImage:(UIImage*)image status:(NSString*)string;
- ローディング中の処理を指定した画像(サイズは28x28固定)とメッセージとともに表示する。表示後1秒経過したら非表示になる。
表示を変えてみる
ViewController.mを以下のように変更してみましょう。
#import "ViewController.h"
// 1.SVProgressHUDをインポート
#import "SVProgressHUD.h"
...
@implementation ViewController
...
// ビューが描画される前に呼ばれるメソッド
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// 「https://classmethod.jp/」の読み込みを開始する
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://classmethod.jp/"]];
[self.webView loadRequest:req];
}
// ページ読込開始直後に呼ばれるデリゲートメソッド
- (void)webViewDidStartLoad:(UIWebView *)webView
{
// 2.SVProgressHUDを表示する
//[SVProgressHUD show];
// 2'.表示するメッセージに「ロード中です」を指定して、アラートビューを表示したときのようなオーバーレイを表示
[SVProgressHUD showWithStatus:@"ロード中です" maskType:SVProgressHUDMaskTypeGradient];
}
// ページ読込終了直後に呼ばれるデリゲートメソッド
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// 3.SVProgressHUDを非表示にする
[SVProgressHUD dismiss];
// 3'.読み込みに成功した旨を表示し、SVProgressHUDを非表示にする
[SVProgressHUD showSuccessWithStatus:@"ロード完了!"];
}
// ページ読込エラー時に呼ばれるデリゲートメソッド
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
// 4.読み込みに失敗した旨を表示し、SVProgressHUDを非表示にする
[SVProgressHUD showErrorWithStatus:@"ロード失敗..."];
}
...
@end
SVProgressHUDを使う際の注意点
- viewDidLoad:メソッドでSVProgressHUDしないこと!
- viewDidLoad:メソッド内で、SVProgressHUDを表示すると、以下の警告がログに表示されます。
Application windows are expected to have a root view controller at the end of application launch
SVProgressHUDでは、マスクタイプにSVProgressHUDMaskTypeNone以外を指定されたときに、ユーザーからの操作を無効にするため、内部的にUIWindowを生成しているので、- viewDidLoad:メソッド内で実行しようとすると起こられちゃいます。なので使用するときは、- viewWillAppear:メソッドか- viewDidAppear:メソッドなど- viewDidLoad:以外から呼び出してあげましょう。
ARCを有効にしましょう!
SVProgressHUDはARCを使用する前提で記述されているので、今回のようにプロジェクトを自体をARC有効にするか、SVProgressHUD.mのコンパイラオプションに-fobjc-arcを指定しましょう。そうしないとSVProgressHUDを非表示にしても実体がのこってしまい、最悪の場合、ユーザからの操作が無効のままになってしまいます。
まとめ
いかがでしょうか?SVProgressHUDがあれば、かっこいいローディング表示がスマートに実装できますね!皆さんも是非使ってみて下さい!