IOS Core Animation Advanced Techniques的學習筆記(四)

來源:互聯網
上載者:User

第五章:Transforms


Affine Transforms

CGAffineTransform是二維的




Creating a CGAffineTransform

主要有三種變化方法旋轉:CGAffineTransformMakeRotation(CGFloat angle)



縮放:CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)


移動:CGAffineTransfZ喎?http://www.bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcm1NYWtlVHJhbnNsYXRpb24oQ0dGbG9hdCB0eCwgQ0dGbG9hdCB0eSk8YnI+Cgo8aW1nIHNyYz0="http://www.2cto.com/uploadfile/Collfiles/20140517/2014051709101437.png" alt="\">



例子5.1 CGAffineTransformMakeRotation

源碼在這裡下載:http://www.informit.com/title/9780133440751

@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees    CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);    self.layerView.layer.affineTransform = transform;}@end


修改 CGAffineTransformMakeScale
- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees    CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.5);    self.layerView.layer.affineTransform = transform;}


修改 CGAffineTransformMakeTranslation
- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees    CGAffineTransform transform = CGAffineTransformMakeTranslation(-50.0, 30.0);    self.layerView.layer.affineTransform = transform;}




Combining Transforms

方法1:使用CGAffineTransformConcat
繼續修改例子5.1
- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees    CGAffineTransform transform1 = CGAffineTransformMakeRotation(M_PI_4);    CGAffineTransform transform2 = CGAffineTransformMakeScale(0.5, 0.5);    CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);    self.layerView.layer.affineTransform = transform;}


方法2:CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)和前面的CGAffineTransformMakeRotation函數相同,也可以混用CGAffineTransform t可以使用CGAffineTransformIdentity函數初始化

例子5.2
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    //create a new transform    CGAffineTransform transform = CGAffineTransformIdentity;        //scale by 50%    transform = CGAffineTransformScale(transform, 0.5, 0.5);        //rotate by 30 degrees    transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);        //translate by 200 points    transform = CGAffineTransformTranslate(transform, 200, 0);        //apply transform to layer    self.layerView.layer.affineTransform = transform;}@end



下面記幾個特殊值1. 首先要知道函數 CGAffineTransformIdentity 初始化的結果

2. 左右翻轉 CGAffineTransformMake(-1,0,0,1,0,0);

3. 以右邊為軸向右翻轉 CGAffineTransformMake(-1,0,0,1,self.layerView.frame.size.width,0);

4. 上下翻轉

CGAffineTransformMake(1,0,0, -1,0,0);



5. 以底邊為軸向下翻轉 CGAffineTransformMake(1,0,0, -1,0,self.layerView.frame.size.height);

6. 轉180° CGAffineTransformMake(-1,0,0, -1,0,0);

7. 例子5.3,向右斜拉 CGAffineTransformMake(1,0, -1,1,0,0);代碼:
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewControllerCGAffineTransform CGAffineTransformMakeShear(CGFloat x, CGFloat y){    CGAffineTransform transform = CGAffineTransformIdentity;    transform.c = -x;    transform.b = y;    return transform;}- (void)viewDidLoad{    [super viewDidLoad];    //shear the layer at a 45-degree angle    self.layerView.layer.affineTransform = CGAffineTransformMakeShear(1, 0);}@end


8. 例子5.3,向左斜拉 CGAffineTransformMake(1, 0,1, 1, 0, 0);



3D Transforms

類似CGAffineTransform,CATransform3D是三維的

CATransform3D又是一個結構。他有自己的一個公式,可以進行套用。

struct CATransform3D

{

CGFloat m11(x縮放), m12(y切變), m13(旋轉), m14( );

CGFloat m21(x切變), m22(y縮放), m23( ), m24( );

CGFloat m31(旋轉), m32( ), m33( ), m34(透視效果,要操作的這個對象要有旋轉的角度,否則沒有效果。正直/負值都有意義);

CGFloat m41(x平移), m42(y平移), m43(z平移), m44( );

};



同樣有三種變換方法
旋轉:CATransform3DMakeRotation(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)首先要先清楚x,y,z是什麼
{x, y, z}組成的向量就是旋轉要使用的軸,angle是旋轉角度

例:原圖

向X軸旋轉45度。 向Y軸旋轉45度。 向Z軸旋轉45度。


向 X軸,Y軸都旋轉45度,就是沿著對角線旋轉。




縮放:CATransform3DMakeScale(CGFloat sx, CGFloat sy, CGFloat sz)

sx:X軸縮放,代表一個縮放比例,一般都是0 ---1之間的數字。

sy:Y軸縮放。

sz:整體比例變換時,也就是m11(sx) == m22(sy)時,若m33(sz)>1,圖形整體縮小,

若0 < m33(sz) < 1,圖形整體放大,

若m33(sz) < 0,發生關於原點的對稱等比變換。


當sx = 1,sy =1時。


當sx = 0.5,sy =0.5時。




變換:CATransform3DMakeTranslation(Gloat tx, CGFloat ty, CGFloat tz)

t' = [1 0 0 0; 0 1 0 0; 0 0 1 0; tx ty tz 1]

1 0 0 0

0 1 0 0

0 0 1 0

tx ty tz 1

豎起來看對應前面的資料結構就很明顯了。


tx:X軸位移位置,往下為正數。

ty:Y軸位移位置,往右為正數。

tz:Z軸位移位置,往外為正數。



可以通過直接修改資料結構,來設定變換效果

struct CATransform3D

{

CGFloat m11, m12, m13, m14;

CGFloat m21, m22, m23, m24;

CGFloat m31, m32, m33, m34;

CGFloat m41, m42, m43, m44;

}

    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);    transform.m11 = 2;

或者修改鍵值

    [myLayer setValue:[NSNumber numberWithInt:0] forKeyPath:@"transform.rotation.x"];




例子5.4
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees along the Y axis    CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);    self.layerView.layer.transform = transform;}@end


修改例子5.4,修改自http://lepetit-prince.net/ios/?p=451
#import "ViewController.h"#import @interface ViewController (){    BOOL front;}@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];    front = YES;    self.layerView.layer.contents = (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    [UIView animateWithDuration:0.5 animations:^{        self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 0.5, 0.0f, 1.0f, 0.0f);    } completion:^(BOOL finished) {        self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 1.5, 0.0f, 1.0f, 0.0f);        self.layerView.layer.contents = front ? (__bridge id)([UIImage imageNamed:@"back.png"].CGImage) : (__bridge id)([UIImage imageNamed:@"front.png"].CGImage);        [UIView animateWithDuration:0.5 animations:^{            self.layerView.layer.transform = CATransform3DMakeRotation(M_PI * 2, 0.0f, 1.0f, 0.0f);        } completion:^(BOOL finished) {            front = !front;        }];    }];}@end
資源檔 front.png back.png


Perspective Projection

前面提到過m34(透視效果,要操作的這個對象要有旋轉的角度,否則沒有效果。正直/負值都有意義)
例子5.5
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *layerView;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];        //create a new transform    CATransform3D transform = CATransform3DIdentity;        //apply perspective    transform.m34 = - 1.0 / 500.0;    //rotate by 45 degrees along the Y axis    transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);        //apply to layer    self.layerView.layer.transform = transform;}@end


如果修改注釋掉旋轉,看看會有什麼結果
    //rotate by 45 degrees along the Y axis    //transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);

例子是用的透視情境是±1.0/d,d鏡頭到景物的距離,取值500~1000效果最好,±代表方向

The Vanishing Point

當景物慢慢遠離鏡頭時,隨著越來越小最終聚集到一點就是Vanishing Point(滅點)
通常情況滅點是在視圖的正中心,或者在包含所有景物範圍的中心。

Core Animation把滅點定義在anchorPoint,所以在變換前需要確定anchorPoint,
尤其需要注意,3D變換時最好確保同一視圖內的所有layey有相同的滅點

The sublayerTransform Property

如果你有多個View或Layer有相同的3D變換,就可以使用sublayerTransform,

sublayerTransform也是CATransform3D,只有sublayers才會響應。

預設值是Identity Transform(CATransform3DIdentity)


例子5.6
@interface ViewController ()@property (nonatomic, weak) IBOutlet UIView *containerView;@property (nonatomic, weak) IBOutlet UIView *layerView1;@property (nonatomic, weak) IBOutlet UIView *layerView2;@end@implementation ViewController- (void)viewDidLoad{    [super viewDidLoad];        //apply perspective transform to container    CATransform3D perspective = CATransform3DIdentity;    perspective.m34 = - 1.0 / 500.0;    self.containerView.layer.sublayerTransform = perspective;    //rotate layerView1 by 45 degrees along the Y axis    CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);    self.layerView1.layer.transform = transform1;        //rotate layerView2 by 45 degrees along the Y axis    CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);    self.layerView2.layer.transform = transform2;}@end


我們挪動一下xib裡的圖片位置:
再看結果

恢複xib檔案,並修改代碼
- (void)viewDidLoad{    [super viewDidLoad];        //apply perspective transform to container//    CATransform3D perspective = CATransform3DIdentity;//    perspective.m34 = - 1.0 / 500.0;//    self.containerView.layer.sublayerTransform = perspective;    //apply perspective    CATransform3D transform1 = CATransform3DIdentity;    transform1.m34 = - 1.0 / 500.0;    transform1 = CATransform3DRotate(transform1, M_PI_4, 0, 1, 0);    self.layerView1.layer.transform = transform1;        //rotate layerView2 by 45 degrees along the Y axis    CATransform3D transform2 = CATransform3DIdentity;    transform2.m34 = - 1.0 / 500.0;    transform2 = CATransform3DRotate(transform2, -M_PI_4, 0, 1, 0);    self.layerView2.layer.transform = transform2;}


結果和最初一樣,但再次修改xib檔案,挪動圖片看結果,比較未改代碼時的效果

大家發現設定sublayerTransform的好處了嗎
1. 可以一次設定所有subLayer的變換效果2. Vanishing Point(滅點)被同時設定在container layer即父圖層的中心,這就意味著無論你怎麼 修改subLayer的position或frame,它們都會保持一個相同的滅點。

Backfaces

例子5.4,我們設定的是旋轉M_PI_4(45°),改為M_PI(180°)
- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees along the Y axis    CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);    self.layerView.layer.transform = transform;}


翻到了layer背面,顯示的是原映像的鏡像圖。由此可見layer是雙面的,並且兩面都被描繪了。因此我們會想到,為什麼要浪費GPU去描繪我們看不見的部分呢。CALayer的另外一個屬性doubleSided可以解決這個問題。
在剛才修改過的例子5.4的代碼中增加doubleSided設定
- (void)viewDidLoad{    [super viewDidLoad];    //rotate the layer 45 degrees along the Y axis    CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);    self.layerView.layer.transform = transform;    self.layerView.layer.doubleSided = NO;}

映像沒有了


Layer Flattening
自己看例子吧,例子5.7和5.8

Solid Objects
也自己看例子吧,例子5.9和5.10





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.