UIView 的旋轉、拖曳與縮放是在 iOS 中很常被使用的技巧,下面我們以 UIImageView 為例,並且透過手指與螢幕的互動來完成這些效果,在互動的部份我們使用手勢辨識 UIGestureRecognizer 物件,你可以參考手勢辨識 UIGestureRecognizer 物件一文,了解 UIGestureRecognizer 的使用方法,並完成相關設定,最後透過 CGAffineTransform 技術來完成 UIImageView 的旋轉、拖曳與縮放動作。
停用 AutoLayout 功能
AutoLayout 這個功能是在 iOS 6.0 才開始出現,當 AutoLayout 啟用時你可以在 Storyboard 的 View Controller Scene 上看到一個藍色的 Constraint 物件,裡頭會記錄許多畫面物件排版的限制與對齊方式,這時,我們無法隨意地移動介面上的物件(在程式執行時使用 CGAffineTransform 也一樣),這時會出現無法以中心點做旋轉、以中心點做縮放,或是無法在 XY 座標空間移動等情形。
View Controller Scene 中的 Constraint 物件 |
停用 AutoLayout 功能的方法,在 Storyboard 中右手邊的 Show the File Inspector 檢視器分頁中,找到 Use AutoLayout 項目,取消勾選即可(預設是開啟)。
取消勾選 Show the File Inspector 中的 Use AutoLayout 項目 |
UIView 的旋轉、拖曳與縮放功能
假設我們的 UIGestureRecognizer 手勢辨識物件都已經設定完成,接下來就是針對手勢辨識成功之後所要採取的反應加以實作。
- 製做暫存變數
在開始之前,我們要先對此類別宣告幾個全域變數當做暫存來使用,目的是為了在取得縮放或是旋轉等向量時,可以將之前的結果與目前所的到的結果做運算,最後才反應在 UIImageView 上。
@interface ViewController : UIViewController {
//旋轉與縮放向量的暫存變數
CGFloat scale, rotate;
}
ps:並不一定非得使用全域變數,如果程式設計的夠好,則可以避掉這一部分,但是將先後所得的兩個向量做運算是無法避免的。
- 旋轉
//旋轉手勢
- (IBAction)doRotate:(UIRotationGestureRecognizer *)sender {
if([sender state] == UIGestureRecognizerStateBegan) {
rotate = sender.rotation;
}
rotate = (sender.rotation - rotate);
CGAffineTransform transform = CGAffineTransformRotate(sender.view.transform, rotate);
[sender.view setTransform:transform];
rotate = sender.rotation;
}
- 拖曳
//拖曳手勢
- (IBAction)doMovement:(UIPanGestureRecognizer *)sender {
[sender.view setCenter:[sender locationInView:self.view]];
}
- 縮放
//縮放手勢
- (IBAction)doScale:(UIPinchGestureRecognizer *)sender {
if([sender state] == UIGestureRecognizerStateBegan) {
scale = sender.scale;
}
scale = 1 + (sender.scale - scale);
CGAffineTransform transform = CGAffineTransformScale(sender.view.transform, scale, scale);
[sender.view setTransform:transform];
scale = [sender scale];
}
在上述程式碼中,旋轉與縮放的原理是一樣的,而在拖曳的部份則是使用更為直覺的 setCenter: 方法函式來做移動,
ps:在此並沒有針對拖曳時的位移差做補償,因為我們假定每次做拖曳的互動時,都是點擊在 UIImageView 的正中心。
其他應用
這邊提供兩個參數來幫助大家做運算,取得目前 UIImageView 旋轉的角度與縮放過後的比例,由於這個方法需要動用到 UIView 的 Layer,所以在使用以下方法前,記得先替專案加上 QuartzCore.framework 與其標頭檔,方法請參考 Xcode 4 新增 Framework 的方法一文。
//取得UIView本身的旋轉角度
CGFloat rotation = [[imageView.layer valueForKeyPath:@"transform.rotation"] floatValue];
//取得UIView本身的縮放比例
CGFloat size = [[imageView.layer valueForKeyPath:@"transform.scale"] floatValue];
ps:取得目前縮放的比例、旋轉角度或是位置,亦可從 imageView.transform 的 a, b, c, d, tx, ty 等屬性進行運算獲得,請參考官方網站的 CGAffineTransform Reference。
沒有留言:
張貼留言