CALayerのcontentsプロパティを設定するとこだけが背景画像を描画する方法では有りません。UIViewのdrawRectメソッドを実装する事でCoreGraphicsやUIKitを利用し、ダイレクトに背景画像を描画することができます。drawRectメソッドにはデフォルト実装が有りませんが、Viewが最初に表示された時に一度呼び出され、以降は更新が必要になった場合に自動的に呼び出されます。明示的に再描画が必要な時はsetNeedsDisplayを呼び出す事で再描画が行われますので、再描画したいからといってコード内からdrawRectメソッドを直接呼び出してはいけません。
UIViewクラスを継承した新しいクラスを作成し、Storyboard上でViewを配置しCustomクラスとして新しく作成したクラスを指定します。
drawRectメソッドでは、青色に塗りつぶされた楕円を描画するコードになっています。(以下コード)
- class Lesson1_7View: UIView {
- // custom draw
- override func drawRect(rect: CGRect) {
- // get context
- let context: CGContext! = UIGraphicsGetCurrentContext()
- // draw with context
- // set fill color
- CGContextSetFillColorWithColor(context, UIColor.blueColor().CGColor)
- // draw ellpise in rect
- CGContextFillEllipseInRect(context, rect)
- }
- }
CALayerにはdelegateプロパティが存在します。それがCALayerDelegateで、displayLayerとdrawLayer メソッドが定義されています。iOSの場合はUIViewを新たに作成するとCALayerも必ず生成されます。この予め生成されているCALayerの場合はUIView側でCALayerDelegateが実装されているため、改めて個別に実装する必要はありません。素直にdrawRectメソッドを実装すれば良いでしょう。
逆に新たに作成したCALayerでカスタム描画したい場合にCALayerDelegateを実装する必要があります。因みに、CALayerDelegateはCALayerクラスにNSObjectのエクステンション(カテゴリ)で定義されており、リファレンスにはInformal Protocolと表現されています。ですので、明示的にCALayerDelegateを採用するコード(クラス定義)を書く必要は無いようです。
- extension NSObject {
- /* If defined, called by the default implementation of the -display
- * method, in which case it should implement the entire display
- * process (typically by setting the `contents' property). */
- func displayLayer(layer: CALayer!)
- /* If defined, called by the default implementation of -drawInContext: */
- func drawLayer(layer: CALayer!, inContext ctx: CGContext!)
- /* Called by the default -layoutSublayers implementation before the layout
- * manager is checked. Note that if the delegate method is invoked, the
- * layout manager will be ignored. */
- func layoutSublayersOfLayer(layer: CALayer!)
- /* If defined, called by the default implementation of the
- * -actionForKey: method. Should return an object implementating the
- * CAAction protocol. May return 'nil' if the delegate doesn't specify
- * a behavior for the current event. Returning the null object (i.e.
- * '[NSNull null]') explicitly forces no further search. (I.e. the
- * +defaultActionForKey: method will not be called.) */
- func actionForLayer(layer: CALayer!, forKey event: String!) -> CAAction!
- }
CALayerはdelegateが設定されているかを調べます。そして、設定されている場合はdisplayLayerメソッドが実装されているか確認します。実装されている場合は呼び出しを行い、もしdisplayLayer実装されていなかった場合はさらにdrawLayerメソッドが実装されているか確認し、実装されている場合はdrawLayerメソッドを呼び出します。
要するに、displayLayer → drawLayer の順で呼び出されるわけですが、displayLayerが実装されている場合はdrawLayerが実装されていても、呼び出されませんので注意が必要です。
新たにCALayerを作成して、そのレイヤをカスタム描画してみます。新たに作成したレイヤには赤色の円を描いています。
- class Lesson1_7ViewController: UIViewController {
- @IBOutlet weak var myView: Lesson1_7View!
- private var newLayer: CALayer!
- override func viewDidLoad() {
- super.viewDidLoad()
- // Do any additional setup after loading the view.
- // create new layer
- newLayer = CALayer()
- newLayer.frame = CGRectMake(0, 0, 100, 100)
- newLayer.contentsScale = UIScreen.mainScreen().scale
- // set delegate
- newLayer.delegate = self
- // add new layer to uiview hosted layer
- myView.layer.addSublayer(newLayer)
- // display new layer
- newLayer.display()
- }
- override func viewDidDisappear(animated: Bool) {
- // clean up
- newLayer.delegate = nil
- }
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- // Dispose of any resources that can be recreated.
- }
- /***
- override func displayLayer(layer: CALayer!) {
- //
- }
- ***/
- override func drawLayer(layer: CALayer!, inContext ctx: CGContext!) {
- NSLog("perform drawLayer.")
- //
- CGContextSetFillColorWithColor(ctx, UIColor.redColor().CGColor)
- CGContextFillEllipseInRect(ctx, layer.frame)
- }
- }
以下コードが新しいレイヤを作成し、delegateを設定しています。
- // create new layer
- newLayer = CALayer()
- newLayer.frame = CGRectMake(0, 0, 100, 100)
- newLayer.contentsScale = UIScreen.mainScreen().scale
- // set delegate
- newLayer.delegate = self
そして、以下がカスタムコード描画部分です。CGContextオブジェクトが引数にあるので、drawLayerメソッドの方を実装しています。drawLayerを呼び出したいため、displayLayerメソッドはコメントアウトにしています。
- override func drawLayer(layer: CALayer!, inContext ctx: CGContext!) {
- NSLog("perform drawLayer.")
- //
- CGContextSetFillColorWithColor(ctx, UIColor.redColor().CGColor)
- CGContextFillEllipseInRect(ctx, layer.frame)
- }
今回使用したサンプルプログラムはGithub上のCoreAnimationLessonに置いています。
GitHub : Core Animation Lesson シリーズ.
AD.
0 件のコメント :
コメントを投稿