web-dev-qa-db-ja.com

CALayerで変換を行う方法

この質問を書く前に、私は

ただし、layerで基本的な変換を行う方法を理解するのにまだ苦労しています。翻訳、回転、拡大縮小の説明と簡単な例を見つけるのは困難でした。

今日、私はついに座ってテストプロジェクトを作成し、それらを理解することにしました。私の答えは以下です。

ノート:

  • 私はSwiftのみを実行しますが、他の誰かがObjective-Cコードを追加したい場合は、私のゲストになります。
  • この時点では、2D変換の理解にのみ関心があります。
30
Suragch

基礎

レイヤー上で実行できるさまざまな変換がいくつかありますが、基本的な変換は次のとおりです。

  • 翻訳(移動)
  • 規模
  • 回転させる

enter image description here

CALayerで変換を行うには、レイヤーのtransformプロパティを_CATransform3D_タイプに設定します。たとえば、レイヤーを翻訳するには、次のようにします。

_myLayer.transform = CATransform3DMakeTranslation(20, 30, 0)
_

Word Makeは、初期変換を作成するための名前に使用されます:CATransform3DMakeTranslation。適用される後続の変換では、Makeが省略されます。たとえば、この回転に続いて平行移動を参照してください。

_let rotation = CATransform3DMakeRotation(CGFloat.pi * 30.0 / 180.0, 20, 20, 0)
myLayer.transform = CATransform3DTranslate(rotation, 20, 30, 0)
_

変換を行う方法の基礎ができたので、各変換方法の例をいくつか見てみましょう。ただし、最初に、もしあなたがそれをいじってみたいなら、私がどのようにプロジェクトをセットアップするかを示します。

セットアップ

以下の例では、シングルビューアプリケーションをセットアップし、UIViewを背景が明るい青色でストーリーボードに追加しました。次のコードを使用して、View Controllerにビューを接続しました。

_import UIKit

class ViewController: UIViewController {

    var myLayer = CATextLayer()
    @IBOutlet weak var myView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // setup the sublayer
        addSubLayer()

        // do the transform
        transformExample()
    }

    func addSubLayer() {
        myLayer.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
        myLayer.backgroundColor = UIColor.blue.cgColor
        myLayer.string = "Hello"
        myView.layer.addSublayer(myLayer)
    }

    //******** Replace this function with the examples below ********

    func transformExample() {

        // add transform code here ...


    }

} 
_

CALayerにはさまざまな種類があります ですが、視覚的に変換がより明確になるように、CATextLayerを使用することにしました。

翻訳する

変換トランスフォームはレイヤーを移動します。基本的な構文は

_CATransform3DMakeTranslation(tx: CGFloat, ty: CGFloat, tz: CGFloat)
_

ここで、txはx座標の変化、tyはyの変化、tzはzの変化です。

enter image description here

IOSでは、座標系の原点は左上にあるため、レイヤーを90ポイント右、50ポイント下に移動する場合は、次のようにします。

_myLayer.transform = CATransform3DMakeTranslation(90, 50, 0)
_

ノート

  • これを上記のプロジェクトコードのtransformExample()メソッドに貼り付けることができます。
  • ここでは2つのディメンションを扱うだけなので、tzは_0_に設定されます。
  • 上の画像の赤い線は、元の場所の中心から新しい場所の中心に向かっています。これは、変換がアンカーポイントに関連して行われ、デフォルトでアンカーポイントがレイヤーの中心にあるためです。

規模

スケール変換は、レイヤーを伸縮させます。基本的な構文は

_CATransform3DMakeScale(sx: CGFloat, sy: CGFloat, sz: CGFloat)
_

ここで、sxsy、およびszは、それぞれx、y、およびz座標をスケーリング(乗算)する数値です。

enter image description here

幅を半分、高さを3倍にしたい場合は、次のようにします

_myLayer.transform = CATransform3DMakeScale(0.5, 3.0, 1.0)
_

ノート

  • 2次元でのみ作業しているため、z座標に1.0を掛けて、影響を受けないようにします。
  • 上の画像の赤い点は、アンカーポイントを表しています。アンカーポイントに対してスケーリングがどのように行われるかに注意してください。つまり、すべてがアンカーポイントに向かってまたはアンカーポイントから離れて引き伸ばされます。

回転

回転変換は、アンカーポイント(デフォルトではレイヤーの中心)を中心にレイヤーを回転させます。基本的な構文は

_CATransform3DMakeRotation(angle: CGFloat, x: CGFloat, y: CGFloat, z: CGFloat)
_

ここで、angleはレイヤーを回転させる角度をラジアン単位で、xy、およびzは回転軸です。軸を0に設定すると、その特定の軸を中心とした回転がキャンセルされます。

enter image description here

レイヤーを時計回りに30度回転させたい場合、次のようにします。

_let degrees = 30.0
let radians = CGFloat(degrees * Double.pi / 180)
myLayer.transform = CATransform3DMakeRotation(radians, 0.0, 0.0, 1.0)
_

ノート

  • 2次元で作業しているため、xy平面のみをz軸の周りに回転させます。したがって、xyを_0.0_に設定し、zを_1.0_に設定します。
  • これにより、レイヤーが時計回りに回転しました。 zを_-1.0_に設定することにより、反時計回りに回転させることができます。
  • 赤い点は、アンカーポイントの場所を示しています。アンカーポイントを中心に回転します。

複数の変換

複数の変換を組み合わせるには、次のような連結を使用できます

_CATransform3DConcat(a: CATransform3D, b: CATransform3D)
_

しかし、私たちは次々とやっていきます。最初の変換では、名前にMakeが使用されます。次の変換はMakeを使用しませんが、前の変換をパラメーターとして使用します。

enter image description here

今回は、前の3つの変換をすべて組み合わせます。

_let degrees = 30.0
let radians = CGFloat(degrees * Double.pi / 180)

// translate
var transform = CATransform3DMakeTranslation(90, 50, 0)

// rotate
transform = CATransform3DRotate(transform, radians, 0.0, 0.0, 1.0)

// scale
transform = CATransform3DScale(transform, 0.5, 3.0, 1.0)

// apply the transforms
myLayer.transform = transform
_

ノート

  • 変換が行われる順序は重要です。
  • すべてがアンカーポイント(赤い点)に関連して行われました。

アンカーポイントと位置に関する注意

上記のすべての変換は、アンカーポイントを変更せずに行いました。ただし、中心以外の点を中心に回転する場合など、変更する必要がある場合があります。ただし、これには少し注意が必要です。

アンカーポイントと位置は両方とも同じ場所にあります。アンカーポイントは、レイヤーの座標系の単位として表され(デフォルトは_0.5, 0.5_)、位置はスーパーレイヤーの座標系で表されます。このように設定できます

_myLayer.anchorPoint = CGPoint(x: 0.0, y: 1.0)
myLayer.position = CGPoint(x: 50, y: 50)
_

位置を変更せずにアンカーポイントのみを設定すると、フレームが変更され、位置が正しい場所に配置されます。より正確には、新しいアンカーポイントと古い位置に基づいてフレームが再計算されます。これは通常、予期しない結果をもたらします。次の2つの記事には、これに関する優れた議論があります。

こちらもご覧ください

98
Suragch