前回(Core Animation Lesson1(Lesson1-1〜)) から引き続きCALayerのプロパティについて調査しました。
本プロパティ値はレイヤ上の背景画像とView上のピクセルサイズ比率を定義するプロパティです。要するにRetinaディスプレイか否かを設定します。contentsScaleの値は通常のディスプレイで1.0を指し、Retinaディスプレイの場合は2.0となります。デフォルト値は1.0です。 この値は以下の様にUIScreenクラスから取得するのが一般的のようです。
// set contentsScale to The Retina value myView.layer.contentsScale = UIScreen.mainScreen().scale
但し、CALayerのcontentsGravityにfill/fit系の拡大縮小のオプションを指定している場合、contentsScaleの値意味を持たなくなるので、注意が必要です。
contentsScale | 概要 |
1.0 | 1Pointが1Pixcelの通常ディスプレイを指す。 |
2.0 | 1Pointが2x2(4Pixcels)のRetinaディスプレイを指す。 |
下の表示イメージは同一画像をRetina/非Retinaで表示してみた例です。
非Retinaディスプレイ[右図→](contentsScale=1.0)
Viewよりも大きい画像はViewからはみ出して表示されてしまいますが、CALayerのmasksToBoundsプロパティを設定することで抑止できます。値はBool値でtrueが設定されるとマスクされます。また、このプロパティはUIViewのclipesToBindsプロパティと同等の機能となります。
以下、サンプルコードです。SegmentedControlボタンでcontentsScale, SwitchボタンでmasksToBoundsのオンオフを設定しています。
import UIKit class Lesson1_4ViewController: UIViewController { @IBOutlet weak var myView: UIView! @IBOutlet weak var mySegmentedControl: UISegmentedControl! @IBOutlet weak var mySwitch: UISwitch! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // image let image = UIImage(named: "chess.png") myView.layer.contents = image?.CGImage myView.layer.contentsGravity = kCAGravityCenter // set default contentsScale to The Retina value myView.layer.contentsScale = UIScreen.mainScreen().scale // set default clip setting myView.layer.masksToBounds = true // set action for segmented control mySegmentedControl.addTarget(self, action: "segmentedValueChanged:", forControlEvents: UIControlEvents.ValueChanged) // set action for switch mySwitch.addTarget(self, action: "switchValueChanged:", forControlEvents: UIControlEvents.ValueChanged) // dump contentsScale println("contentsScale : \(myView.layer.contentsScale)") println("image Scale : \(image?.scale)") println("UIScreen scale: \(UIScreen.mainScreen().scale)") } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func segmentedValueChanged(target: UISegmentedControl) { if (target.selectedSegmentIndex == 0) { myView.layer.contentsScale = 1.0 } else { myView.layer.contentsScale = 2.0 } } func switchValueChanged(target: UISwitch) { if target.on { myView.layer.masksToBounds = true } else { myView.layer.masksToBounds = false } } }
指定された範囲をクリップするイメージですが、大きな画像ファイルに小さいイメージをパックする事で、小さいイメージを個々に読み込むより、大きなファイルを一回だけ読み込ませる方が読み込み時間、使用メモリ量のパフォーマンスに優れています。ゲームの様に小さな画像を多数使用する場合にメリットが大きい様です。また、contentsRectの単位はpoint単位では無くunit coordinate単位であることにも注意が必要です。
以下の図は、1枚の画像ファイルにAとBが横並びで描画されています。その画像ファイルを1回だけ読み込み、contentsRectプロパティを利用し元画像の必要な部分(AとB)をクリッピングし縦並びで表示しています。
以下、ソースコードですが、CALayerのcontentsには元画像を設定しcontentsRectプロパティにてそれぞれ必要な領域を指定しています。contentsRectはCGRect型で指定する値はUnitCoordinate単位となります。UnitCoordinate単位については後述します。
import UIKit class Lesson1_5ViewController: UIViewController { @IBOutlet weak var viewA: UIView! @IBOutlet weak var viewB: UIView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // load image once. let image = UIImage(named: "AB.png") // A viewA.layer.contents = image?.CGImage viewA.layer.contentsRect = CGRectMake(0, 0, 0.5, 1.0) // B viewB.layer.contents = image?.CGImage viewB.layer.contentsRect = CGRectMake(0.5, 0, 0.5, 1.0) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
Coordinate Type | 概要 |
Point | Pointは仮想的なPixelであり、デバイスの解像度によって変化する。通常デバイスでは1Pointが1Pixelとなるが、Retina Display では、2x2の計4Pixelsとなる。 |
Unit | Unit単位は0.0〜1.0まで指定可能な比率で指定する便利な指定方法で、1.0が100%のサイズを意味している。比率で指定しているため、元の画像のサイズが変更されても再調整する必要が無いのが利点。 |
以下図はUnit単位を表しています。右下が最大値である(1, 1)を表し、中心点は(0,5, 0,5)となります。
このプロパティは、プロパティ名から想像される機能と異なり、イメージの伸縮エリアについての設定が行われます。これは、インターフェースビルダーからも設定可能な値で、デフォルト値はUnit単位で(0,0,1,1)となり全域が一様に伸縮する設定となっています。contentCenterで指定した矩形の外側はそれぞれの位置により伸縮の方向が異なります。
以下のイメージを考えてみます。分かりやすいように方眼紙のようなマス目をが描かれているイメージを描画しています。この画像イメージにcontentsCenterプロパティを指定してみます。
図(↓)contentsCenterとして(0.25, 0.25, 0.5, 0.5)を指定しました。方眼紙のイメージで分かりやすいかと思ったのですが、全然分かり難いですね。良く見てみると分かりますが、方眼紙のマス目の高さや幅ががcontentsCenterで指定した矩形内と外で異なっていることに気づくと思います。
図(↓)contentsCenterで指定した矩形枠内と外での引き伸ばしについて、赤枠は縦横均等、緑は縦、青は横、黄色は無しとなっています。
contentsCenterはViewのプロパティとしてGUIからも設定可能です。
今回使用したサンプルプログラムはGithub上のCoreAnimationLessonに置いています。
GitHub : Core Animation Lesson シリーズ.
0 件のコメント :
コメントを投稿