第五章:Transformsios
Affine Transforms
CGAffineTransform是二維的
Creating a CGAffineTransform
主要有三種變化方法
旋轉:
CGAffineTransformMakeRotation(CGFloat angle)
縮放:
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
移動:
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
例子5.1 CGAffineTransformMakeRotationxcode
源碼在這裏下載:http://www.informit.com/title/9780133440751數據結構
- @interface ViewController ()
-
- @property (nonatomic, weak) IBOutlet UIView *layerView;
-
- @end
-
- @implementation ViewController
-
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI_4);
- self.layerView.layer.affineTransform = transform;
- }
-
- @end
修改 CGAffineTransformMakeScale
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- CGAffineTransform transform = CGAffineTransformMakeScale(0.5, 0.5);
- self.layerView.layer.affineTransform = transform;
- }
修改 CGAffineTransformMakeTranslation
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- CGAffineTransform transform = CGAffineTransformMakeTranslation(-50.0, 30.0);
- self.layerView.layer.affineTransform = transform;
- }
Combining Transforms
方法1:使用CGAffineTransformConcat
繼續修改例子5.1
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- 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];
-
-
- CGAffineTransform transform = CGAffineTransformIdentity;
-
-
- transform = CGAffineTransformScale(transform, 0.5, 0.5);
-
-
- transform = CGAffineTransformRotate(transform, M_PI / 180.0 * 30.0);
-
-
- transform = CGAffineTransformTranslate(transform, 200, 0);
-
-
- 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);app
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 ViewController
-
- CGAffineTransform CGAffineTransformMakeShear(CGFloat x, CGFloat y)
- {
- CGAffineTransform transform = CGAffineTransformIdentity;
- transform.c = -x;
- transform.b = y;
- return transform;
- }
-
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- self.layerView.layer.affineTransform = CGAffineTransformMakeShear(1, 0);
- }
-
- @end
8. 例子5.3,向左斜拉
CGAffineTransformMake
(1, 0,1, 1, 0, 0);
3D Transforms
相似CGAffineTransform,CATransform3D是三維的
CATransform3D又是一個結構。他有本身的一個公式,能夠進行套用。ide
struct CATransform3Dsvg
{函數
CGFloat m11(x縮放), m12(y切變), m13(旋轉), m14( );oop
CGFloat m21(x切變), m22(y縮放), m23( ), m24( );atom
CGFloat m31(旋轉), m32( ), m33( ), m34(透視效果,要操做的這個對象要有旋轉的角度,不然沒有效果。正直/負值都有意義);spa
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];
-
-
- CATransform3D transform = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
- self.layerView.layer.transform = transform;
- }
-
- @end
- #import "ViewController.h"
- #import <QuartzCore/QuartzCore.h>
-
- @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];
-
-
- CATransform3D transform = CATransform3DIdentity;
-
-
- transform.m34 = - 1.0 / 500.0;
-
-
- transform = CATransform3DRotate(transform, M_PI_4, 0, 1, 0);
-
-
- self.layerView.layer.transform = transform;
- }
-
- @end
若是修改註釋掉旋轉,看看會有什麼結果
例子是用的透視場景是±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];
-
-
- CATransform3D perspective = CATransform3DIdentity;
- perspective.m34 = - 1.0 / 500.0;
- self.containerView.layer.sublayerTransform = perspective;
-
-
- CATransform3D transform1 = CATransform3DMakeRotation(M_PI_4, 0, 1, 0);
- self.layerView1.layer.transform = transform1;
-
-
- CATransform3D transform2 = CATransform3DMakeRotation(-M_PI_4, 0, 1, 0);
- self.layerView2.layer.transform = transform2;
- }
-
- @end
咱們挪動一下xib裏的圖片位置:
再看結果
恢復xib文件,並修改代碼
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
-
-
- CATransform3D transform1 = CATransform3DIdentity;
- transform1.m34 = - 1.0 / 500.0;
- transform1 = CATransform3DRotate(transform1, M_PI_4, 0, 1, 0);
- self.layerView1.layer.transform = transform1;
-
-
- 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];
-
-
- 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];
-
-
- 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