Watson's Blog

CGGradient を使ってグラデーションを作る

| Comments

RubyMotion で CGGradient を使ってグラデーションを作る際に 2 点ほどポイントがありそうです。

1. Pointer クラスを使用する

CGGradient オブジェクトを作成する際に使用する関数 CGGradientCreateWithColorComponentsCGFloat 型の配列を受け取ります(変数 components, locations に注目してください)。

1
2
3
4
5
6
CGGradientRef CGGradientCreateWithColorComponents(
   CGColorSpaceRef space,
   const CGFloat components[],
   const CGFloat locations[],
   size_t count
);

もし引数が Ruby の Array クラスや、Objective-C の NSArray を受け取るなら話は簡単なのですが、ここでは CGFloat 型の配列なので、RubyMotion で用意されている Pointer クラスを使い CGFloat 型の配列と同等のものを作ります。以下のようなコードになります。

1
float_array = Pointer.new(:float, size)

2. kCGGradientDrawsXXXX 定数

CGGradient では kCGGradientDrawsBeforeStartLocationkCGGradientDrawsAfterEndLocation という定数が用意されています。どちらも小文字から始まる定数です。

RubyMotion では英小文字から始まる定数は、一文字目を大文字に書き換えて利用してあげる必要があります。

kCGGradientDrawsAfterEndLocationKCGGradientDrawsAfterEndLocation になります。

いざ動かしてみる

app_delegate.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Array
  def to_pointer(type)
    # Ruby の Array オブジェクトを Pointer クラスを使ったものに変換
    pointer = Pointer.new(type, self.size)
    self.each_with_index do |v, i|
      pointer[i] = v
    end
    pointer
  end
end

class GradientView < UIView
  def drawRect(rect)
    super

    context = UIGraphicsGetCurrentContext()
    CGContextSaveGState(context)

    CGContextAddRect(context, self.frame)
    space = CGColorSpaceCreateDeviceRGB()

    comp = [
        0.0, 0.0, 1.0, 1.0, # Blue
        1.0, 0.0, 0.0, 1.0, # Red
        0.0, 1.0, 0.0, 1.0  # Green
    ]
    components = comp.to_pointer(:float)

    loc = [0.0, 0.5, 1.0]
    locations = loc.to_pointer(:float)

    count = loc.size
    frame = self.bounds
    start_point = frame.origin
    end_point = CGPointMake(frame.origin.x + frame.size.width, frame.origin.y)
    gradient = CGGradientCreateWithColorComponents(space, components, locations, count)

    CGContextDrawLinearGradient(context,
                                gradient,
                                start_point,
                                end_point,
                                KCGGradientDrawsAfterEndLocation) # 定数を英大文字で始める
    CGContextRestoreGState(context)
  end

end

class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
    @window.rootViewController = UIViewController.alloc.initWithNibName(nil, bundle: nil)

    @view = GradientView.alloc.initWithFrame(CGRectMake(10, 10, 100, 100))
    @window.rootViewController.view.addSubview(@view)
    @window.makeKeyAndVisible

    true
  end
end

次のような View が表示されるはずです。

Gradient

Comments