職人が教える!iOSアプリ開発で使いこなしたいとっておきのOSS

第5回 グラデーション描画や色のアニメーションの実装を簡単にする色処理関連の便利OSS3選

この記事を読むのに必要な時間:およそ 4.5 分

2つのUIColorの間でクロスフェードさせるUIColorのカテゴリ

UIColor-CrossFaceを使うと,指定した比率で2つのUIColorの間でクロスフェードさせることができます。

……と文章で書いても何のことかわかりにくいと思うので,まずは下記URLからソース一式をダウンロードし,⁠UIColorCrossFadeDemo⁠というプロジェクトをビルド&実行してみてください。

画像

このような画面が現れ,画面内のスライダーを右に動かすと,以下のようにスライダーの値に従って背景が赤から青へクロスフェードします。

画像

これは,Flashで言えばシンボルの「カラー効果」プロパティに値を指定して色を変えることに相当していて,こういったことを実現するためのUIColorのカテゴリが,UIColor-CrossFaceです。

APIもとてもわかりやすく

+ (UIColor *)colorForFadeBetweenFirstColor:(UIColor *)firstColor 
                               secondColor:(UIColor *)secondColor 
                                   atRatio:(CGFloat)ratio;

最初の色,最後の色をUIColor型で指定し,あとは比率を指定すれば,⁠最初の色から最後の色までクロスフェードする際の指定比率における色」が返されます。

サンプルコードではこのratio引数に渡す値としてスライダーの値を用いていますが,たとえば本連載の第1回でご紹介したトゥイーンライブラリを用いることで,イージング付きでクロスフェードするアニメーションを実現することもできます。

ちなみに,APIには,

+ (NSArray *)colorsForFadeBetweenFirstColor:(UIColor *)firstColor 
                                  lastColor:(UIColor *)lastColor 
                          withRatioEquation:(float (^)(float))equation
                                    inSteps:(NSUInteger)steps;

といったように,比率を直接渡すのではなく,比率を求める計算式を渡すためのメソッドも用意されているので,カスタムイージングカーブを実現するための式を自作して渡すことも可能です。

カテゴリ内部で色の計算を行っている部分の実装は,下記のようになっています。

const CGFloat *firstColorComponents = CGColorGetComponents(firstColor.CGColor);
const CGFloat *secondColorComponents = CGColorGetComponents(secondColor.CGColor);

CGFloat interpolatedComponents[CGColorGetNumberOfComponents(firstColor.CGColor)] ;
for (NSUInteger i = 0; i < CGColorGetNumberOfComponents(firstColor.CGColor); i++)
{
    interpolatedComponents[i] = firstColorComponents[i] * (1 - ratio) + secondColorComponents[i] * ratio;
}

最初の色,最後の色それぞれのcolor components(RGBAの各値)を取り出し,各チャネルごとに指定比率でのブレンドを行う,というシンプルなものです。

ところで,実はこのカテゴリを使用しなくても,Core Animationを用いれば,CALayerの backgroundColorやshadowColorなどは,下記のようなコードで色のクロスフェードを実現できてしまいます。

CABasicAnimation *bgColorAnimation = [CABasicAnimation  animationWithKeyPath:@"backgroundColor"];
bgColorAnimation.toValue = (id)[UIColor redColor].CGColor;
[self.view.layer addAnimation:bgColorAnimation forKey:@"bgColorAnimation"];

ただ,この方法はあくまでCore Animationでアニメーション可能なプロパティ※をアニメーションさせたい場合にしか用いることができないので,UIColor型であればどんなプロパティに対しても適用可能なUIColor-CrossFadeのほうが汎用性は高いと言えます(たとえば,サンプルにあったようにスライダーの値に合わせて色を変化させたい場合や,UILabelのtextColorプロパティに適用したい場合など⁠⁠。

Core Animationでアニメーション可能なプロパティ一覧は,AppleのドキュメントであるCore Animation Programming Guide⁠Animatable Properties⁠の項で一覧を確認することができます。

今回紹介したUIColor-CrossFade自体は,たった百数行のシンプルなものですが,この発想を応用し,色んな自前パラメータをアニメーションさせるカテゴリを自作してみても楽しいかもしれません。

色の重ね合わせやCSSカラー名での色の指定ができるようになるUIColorのカテゴリ

最後に,UIColorの便利な拡張機能を色々と詰め合わせたカテゴリ⁠uicolor-utilities⁠を紹介します。

たとえば,UIColorのカテゴリやマクロでは定番の,16進カラーコード(Hexカラー)との相互変換機能も,UInt32型,NSString型両方に対応して備えています。

@property (nonatomic, readonly) UInt32 rgbHex;
- (NSString *)hexStringFromColor;
+ (UIColor *)colorWithRGBHex:(UInt32)hex;
+ (UIColor *)colorWithHexString:(NSString *)stringToConvert;

色の重ね合わせ機能も備えており,PhotoshopやFireworksのブレンドモードではおなじみの,乗算,加算,比較(暗⁠⁠,比較(明)といった計算方法別にメソッドが用意されています。

- (UIColor *)colorByMultiplyingByRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
- (UIColor *)       colorByAddingRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
- (UIColor *) colorByLighteningToRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
- (UIColor *)  colorByDarkeningToRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;

ちょっとした機能ですが,次のようなメソッドも持っています。

- (NSString *)stringFromColor;

この内部実装は下記のようになっており,チャネルごとの値を(チャネル数を判別して)NSString型で出力してくれるので,ログ出力に便利です。

switch (self.colorSpaceModel) {
    case kCGColorSpaceModelRGB:
        result = [NSString stringWithFormat:@"{%0.3f, %0.3f, %0.3f, %0.3f}", self.red, self.green, self.blue, self.alpha];			
        break;
    case kCGColorSpaceModelMonochrome:
        result = [NSString stringWithFormat:@"{%0.3f, %0.3f}", self.white, self.alpha];
        break;
    default:
        result = nil;
}

下記メソッドでは,輝度成分を抽出しグレースケール化したUIColorを返します。

- (UIColor *)colorByLuminanceMapping

「輝度」の求め方は諸々あるのですが,ソースで確認したところ,RGB にかけている係数の値から,YPbPr の計算式に基づいているようです。

“aliceblue⁠⁠antiquewhite⁠などのCSSカラー名からUIColorを取得できるメソッドも備えています。

+ (UIColor *)colorWithName:(NSString *)cssColorName;

UIColor の標準メソッドではblackColorやredColorなどごくごく基本的な色を出力する機能しかなく,もうちょっと違う色味を出したいとなると直接RGB値から生成するしかありませんでした。CSSカラーはWeb上にたくさんの色見本があるので,Webで気に入った色を探しつつそのまま色名を指定する,といったことができるようになります。そして,RGB値を指定する場合よりソースコードから色味を想像しやすいというメリットもあります。

uicolor-utilitiesは下記URLよりダウンロードできます。

まとめ

今回は「色処理関連の便利OSS」という括りで,グラデーション描画のヘルパークラスLBGradient,2つのUIColorの間でクロスフェードさせるUIColorのカテゴリUIColor-CrossFace,色の重ね合わせやCSSカラー名での色の指定ができるようになるUIColorのカテゴリuicolor-utilitiesの3つのOSSを紹介しました。

今回ご紹介したOSSではそれほど複雑な機能を代行してくれているわけではないのですが,そのぶん内部のソースコードも把握しやすく,使い回しや応用がききやすいのではと思います。モック開発時などにサクッといい感じに色をつけたい場合に,あるいはヘルパークラスを自作する際の参考に,何かしらの形で皆様の開発のお役に立てば幸いです。

著者プロフィール

堤修一(つつみしゅういち)

1978年生まれ。京都大学工学部を卒業後,同大学院修了。その後,NTTデータにて音声認識技術の研究開発,キヤノンにて画像処理機能の設計に携わる。

2010年より面白法人カヤックに入社。3年間ほぼiOSアプリ開発に専念し,フルスクラッチで開発しリリースしたアプリは30本以上。代表作は150万ユーザを突破した「バウンドモンスターズ」,AppStore Best of 2012を獲得した「タップ忍者」,カンヌ国際広告祭でブロンズを獲得した「Domino's App」など。

現在は,米国シリコンバレーのマウンテンビューにあるAppSocially社の一員として活躍中。

著書=『iOSアプリ開発 達人のレシピ100―開発現場で実証された実用コード集』

ブログ=Over&Outその後

Github=shu223

Twitter=shu223