アプリを作る上で、プログレスバーを使う機会は比較的多い。
そういう時に、オリジナルのデザインを適用したいと思うことも多々ある。
この画像でいうところの下のプログレスバーだ。
プログレスバー_ss1
デザインにこだわりのある顧客の場合は、ほぼ確実にそういうリクエストがあるだろう。
progressImageやtrackImageを設定すれば、ある程度のデザインには出来るが、やはり物足りなさは否めない。
そこで今回はこのオリジナルのプログレスバーを作成する。

画像を用意する
まず最初に2つの画像を用意しよう。
progress_bg
progress
上が背景用で下が率に応じて表示するためのものだ。
もちろん、Retina用の画像も別途用意するが、ここでは省略する。

オリジナルのプログレスバー用のクラスを作成する
次はオリジナルのプログレスバーを表示するためのクラスを作成する。
これは基本的にStoryboardで使用することを前提で、クラス名はImageProgressViewとする。
#import <UIKit/UIKit.h>

@interface ImageProgressView : UIView

- (CGFloat)progress;
- (void)setProgress:(CGFloat)progress;

@end
#import "ImageProgressView.h"

@implementation ImageProgressView
{
    UIImage *_bg;
    UIImage *_front;
    CGFloat _ratio;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self)
    {
        // プログレスバーに必要な画像を読み込む
        _bg = [UIImage imageNamed:@"progress_bg.png"];
        _front = [UIImage imageNamed:@"progress.png"];
        _ratio = 0;
    }
    return self;
}

/**
 * 描画する。
 */
- (void)drawRect:(CGRect)rect
{
    // 背景描画
    [_bg drawAtPoint:CGPointZero];
    
    if (_ratio == 0)
        return;
    
    // バー描画
    UIImage *croppedImage;
    CGSize size = CGSizeMake(_front.size.width * _ratio, _front.size.height);
    
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    [_front drawAtPoint:CGPointZero];
    croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    [croppedImage drawAtPoint:CGPointZero];
}

/**
 * 率を取得する。
 */
- (CGFloat)progress
{
    return _ratio;
}

/**
 * 率を設定する(0.0 - 1.0)
 */
- (void)setProgress:(CGFloat)progress
{
    if (progress < 0)
        progress = 0;
    else if (progress > 1)
        progress = 1;
    
    _ratio = progress;
    [self setNeedsDisplay];
}
まず、背景用、前面用、率用のインスタンス変数を用意する。
これらは外部から直接アクセスする必要は無いので、ImageProgressView.mに宣言する。

次に初期化部分を見てみよう。
画像ファイル名がベタ書きにしてある。
出来ることなら引数でファイル名を渡してあげたいところだが、Storyboadで使用したいのでこのようにしてある。

次は描画処理部分を見てみよう。
率に応じて前面用の画像を切り出して、それを背景の上に重ねるように描画する。

UIGraphicsBeginImageContextWithOptions()を使用している箇所は重要だ。
こうすることでRetinaディスプレイの対応が自動的に行われる。

これでクラスは完成だ。
実際に使ってみることにしよう。

ImageProgressViewを使用する
まずはStoryboardでこのようにUIViewを配置する。
プログレスバー_ss2
UIViewのサイズは画像と同じ300x50とする。

次にそのUIViewのIdentity inspertorでCustom Classに先ほど作成したImageProgressViewを指定する。
プログレスバー_ss3

次にImageProgressViewにアクセスするためにpropertyを作成する。
プログレスバー_ss4
このままだとImageProgressViewが認識されずエラーが出るので、@classを追加する。
プログレスバー_ss5
後はViewControllerから好きなように呼び出すだけだ。

#import "ViewController.h"
#import "ImageProgressView.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    [self.progressView setProgress:0.45];
}

@end

ここではシンプルにviewDidLoadで45%に設定するようにしてある。
結果はこうだ。
プログレスバー_ss6
期待通りの表示となった。