ぴよログ

↓に移転したのでこっちは更新されません、多分。

iOSでUIButtonの選択時の背景色をグラデーションにする

移転しました →

UIButtonの背景色をグラデーションにする方法は簡単です。適当にググればでてきますし。ですが、ボタンをタップしたときの色をグラデーションにする方法はちょっと面倒でトリッキーだったので紹介します。

その前に、背景色を普通にグラデーションにする方法はこちら。

Objective-C - UIButton をグラデーションにする - Qiita [キータ]

UIButtonのサブクラスを作る

オリジナルのButton用クラスを用意しておくと便利です。

// GradientButton.h
@interface GradientButton : UIButton


@end
// GradientButton.m
#import "GradientButton.h"

@implementation GradientButton

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
   
    [self setupBackgroundGradientForState:UIControlStateNormal
                                   colors:@[(id)[[UIColor cyanColor] CGColor],
                                            (id)[[UIColor greenColor] CGColor]]];
    [self setupBackgroundGradientForState:UIControlStateHighlighted
                                   colors:@[(id)[[UIColor magentaColor] CGColor],
                                            (id)[[UIColor redColor] CGColor]]];
    return self;
}

- (void)setupBackgroundGradientForState:(NSUInteger)state
                                 colors:(NSArray*)colors
{
    CAGradientLayer *gradient = [[CAGradientLayer alloc] init];
    gradient.frame = self.bounds;
    gradient.colors = colors;
   
    UIGraphicsBeginImageContext(CGSizeMake(1, [self bounds].size.height));
    [gradient renderInContext: UIGraphicsGetCurrentContext()];
    UIImage *bgImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self setBackgroundImage:bgImage forState:state];
} 

基本的にはUIViewの背景色をグラデーションにするときと同じく、CAGradientLayerを用いてグラデーションを設定します。凝ったグラデーションを作る場合はCAGradientLayerでいろいろやっている人を探せば見つかると思うので丸投げです。

で、今回の肝なんですが、作ったCAGradientLayeraddSubLayerするのではなく、CAGradientLayerからUIImageを生成して背景画像に設定してしまうという方法をとっています。背景画像の設定のときにUIControlStateを渡すのでUIControlStateHighlightedを渡してあげれば、タップ時の背景画像をグラデーションにするという目的を果たすことができます。

ストーリーボードやXIBを使っている場合には、配置したUIButtonのカスタムクラスをこのGradientButtonクラスにしてあげれば良いです。

結果

タップがわかりづらいかもですが、ちゃんとタップ時の色をグラデーションにできていると思います。

余談:ハイライト時のエフェクトを無くす

上のGIF画像を見ると、タップしたときの背景色が指定したものよりも薄いことがわかると思います。これはデフォルトでつけられているエフェクトによってぼんやりと薄くなってしまっているわけですね。

せっかく背景色をグラデーションにカスタマイズしたのに勝手にエフェクト掛けられたら困ると思い、エフェクトを消す方法をstackoverflowあたりでググって見ると、インスペクタでHighlighted Adjusts Imageをオフにする、またはコードで

button.adjustsImageWhenHighlighted = NO;

のようにすればいいよ、ということでした。

ですが、それは効かず!

結局ボタンタイプをSystemからCustomにすればエフェクトはなくなりました。

設定後のグラデーションの様子はこちら。タップ時の色が濃くなったのがわかると思います。