31

私がやろうとしていることは、それで十分簡単なはずです。古いレコードの2Dトップダウンビューを作成しました。X軸で回転(元に戻す)してから、Z軸を中心に回転させます。

CATransform3Dが本体に含まれているすべての質問をここで読みました。また、SteveBakerの「Matricescanbe your friends」の記事と、BillDudneyの本「CoreAnimationfor Mac OS X andtheiPhone」を読みました。BradLarsonの「 「トラックボールなしの3D回転」にはすべて正しいコードがありますが、彼はユーザーに3軸すべての調整を許可しているため、コードを1次元(回転したz軸)に縮小するのに苦労しています。 )。

これが私がテストしている画像ですが、詳細が問題にとって重要であるというわけではありません。

ゴールドレコード

私はそれを通常の方法で画面に表示します:(UIViewのサブクラスで)

- (void)awakeFromNib
{
    UIImage *recordImage = [UIImage imageNamed:@"3DgoldRecord"];
    if (recordImage) {
        recordLayer = [CALayer layer];
        [recordLayer setFrame:CGRectMake(0.0, 0.0, 1024, 1024)];
        [recordLayer setContents:(id)[[UIImage imageNamed:@"3DgoldRecord"] CGImage]];
        [self.layer addSublayer:recordLayer];
    }
}

これが最初のテストで、画面に表示されるだけです;-)

次に、「レイバック」するために、レイヤーのX軸を中心に回転する変換を適用し、レイヤーのコンテンツを画像に設定した後、サブレイヤーを追加する前に次のコードを挿入します。

    CATransform3D myRotationTransform = 
                    CATransform3DRotate(recordLayer.transform,
                                        (M_PI_2 * 0.85), //experiment with flatness
                                        1.0, // rotate only across the x-axis
                                        0.0, // no y-axis transform
                                        0.0); //  no z-axis transform
    recordLayer.transform = myRotationTransform;        

それは期待通りに機能しました:レコードはうまくリラックスしています。

そして、次のステップとして、レコードを回転させるために、このアニメーションをtouchesEndedイベントに関連付けましたが、テスト/学習フェーズを終了すると、このローテーションはユーザーの制御下に置かれなくなります。

CATransform3D currentTransform = recordLayer.transform; // to come back to at the end
CATransform3D myRotationTransform = 
                CATransform3DRotate(currentTransform,
                                    1.0, // go all the way around once
                                    (M_PI_2 * 0.85),    // x-axis change
                                    1.00,    // y-axis change ?
                                    0.0);   // z-axis change ?
recordLayer.transform = myRotationTransform;        
CABasicAnimation *myAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
myAnimation.duration = 5.0;
myAnimation.fromValue = [NSNumber numberWithFloat:0.0];
myAnimation.toValue = [NSNumber numberWithFloat:M_PI * 2.0];
myAnimation.delegate = self;
[recordLayer addAnimation:myAnimation forKey:@"transform.rotation"];

だから私がハングアップしているのはCATransform3DRotate呼び出しのベクトルであると確信しています(私を信じてください:私は変更を監視するためにそのベクトルで単純な変更を試みてきました...ここにリストされているのは単に最後の変更です私は試した)。私が理解しているように、変換でのx、y、zの値は、本質的に、アニメーション中に渡された値の値の範囲であるfromValueからtoValueまでのパーセンテージです。

私がこれを理解している正しい軌道に乗っている場合、これを単一の変換で表現することは可能ですか?または、アニメーションの有効なフレームごとに、元の直立した画像をz軸を中心にわずかに回転させてから、x軸を回転させて結果を配置する必要がありますか?変換の組み合わせについての質問/回答を見ましたが、それはスケール変換とそれに続く回転変換でした。私は変換の変換をいじりましたが、私が得るべきだと思うことをしていません(つまり、ある変換の結果を次の変換引数に渡すと、一方を完全に実行してからもう一方をアニメーション化するように見えました)。

4

2 に答える 2

63

CATransformLayerこれは、イメージ ビューのレイヤーの親としてを使用する場合に最も簡単です。CATransformLayerそのため、レイヤーとして使用するカスタム ビュー サブクラスが必要になります。これは簡単です:

@interface TransformView : UIView

@end

@implementation TransformView

+ (Class)layerClass {
    return [CATransformLayer class];
}

@end

TransformViewペン先にaを入れ、UIImageViewのサブビューとして aを追加しますTransformView。これらのビューを View Controller 内のtransformViewおよび と呼ばれるアウトレットに接続しますdiscView

ビュー コントローラで、transformView( を設定して) 遠近法を適用するように の変換を設定m34し、X 軸の傾きを設定します。

- (void)viewDidLoad
{
    [super viewDidLoad];
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = -1 / 500.0;
    transform = CATransform3DRotate(transform, .85 * M_PI_2, 1, 0, 0);
    self.transformView.layer.transform = transform;
}

キー パスのアニメーションを に追加transform.rotation.zdiscViewviewWillAppear:で削除しviewDidDisappear:ます。

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    animation.fromValue = [NSNumber numberWithFloat:0];
    animation.toValue = [NSNumber numberWithFloat:2 * M_PI];
    animation.duration = 1.0;
    animation.repeatCount = HUGE_VALF;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
    [self.discView.layer addAnimation:animation forKey:@"transform.rotation.z"];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [self.discView.layer removeAllAnimations];
}

結果:

スピニングディスク

アップデート

Swift プレイグラウンドのデモは次のとおりです。

import UIKit
import XCPlayground

class TransformView: UIView {
    override class func layerClass() -> AnyClass {
        return CATransformLayer.self
    }
}

let view = UIView(frame: CGRectMake(0, 0, 300, 150))
view.backgroundColor = UIColor.groupTableViewBackgroundColor()
XCPlaygroundPage.currentPage.liveView = view

let transformView = TransformView(frame: view.bounds)
view.addSubview(transformView)

var transform = CATransform3DIdentity
transform.m34 = CGFloat(-1) / transformView.bounds.width
transform = CATransform3DRotate(transform, 0.85 * CGFloat(M_PI_2), 1, 0, 0)
transformView.layer.transform = transform

let image = UIImage(named: "3DgoldRecord")!
let imageView = UIImageView(image: image)
imageView.bounds = CGRectMake(0, 0, 200, 200)
imageView.center = CGPointMake(transformView.bounds.midX, transformView.bounds.midY)
transformView.addSubview(imageView)

let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.fromValue = 0
animation.toValue = 2 * M_PI
animation.duration = 1
animation.repeatCount = Float.infinity
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
imageView.layer.addAnimation(animation, forKey: animation.keyPath)

質問の画像をプレイグラウンドの Resources フォルダーにコピーし、名前を付けます3DgoldRecord.png。結果:

遊び場の結果

于 2012-02-24T05:37:42.507 に答える
0

recordLayer をスーパーレイヤーでラップすることを検討してください。x 軸の回転をスーパーレイヤーに適用し、z 軸の回転アニメーションを recordLayer に追加します。

于 2012-02-24T03:34:43.907 に答える