2013-01-10 40 views
1

我對iOS仍然很新,但我無法弄清楚爲什麼這種方式不起作用。從UIimageview創建CGpath,使用旋轉和縮放作爲cglayer掩碼使用

我有2個獨立的UIImageView的

  1. 的 '背景'。這是一張將應用圖層蒙版的圖片,以便您只能看到圖像的一部分。
  2. '面具圖像'這是它自己的獨立圖像,可以旋轉,平移,捏縮放。旋轉/縮放的代碼工作正常,並且是標準代碼。

我所要做的是創建到當前位置/旋轉/的「掩模圖像」

這裏是我抓住了「掩模圖像」的位置代碼和規模相匹配的CGPath創建一個CGPAth用作圖層蒙版。

如果你去Xcode和做一個新的 '單一視圖的應用' 項目,這裏是視圖控制器

ViewController.h的全複製粘貼:

#import <UIKit/UIKit.h> 

@interface ViewController : UIViewController <UIGestureRecognizerDelegate> 
{ 
    UIImageView *makskedImageView; 
    UIImageView *maskImageView; 
} 

@end 

ViewController.m

#import "ViewController.h" 
#import <QuartzCore/QuartzCore.h> 

@interface ViewController() 

@end 

@implementation ViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 
    UIImage *sourceImage = [UIImage imageNamed:@"forest.jpg"]; 
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, (sourceImage.size.width/2), (sourceImage.size.height/2))]; 
    imageView.image = sourceImage; 

    [self.view addSubview:imageView]; 

    makskedImageView = imageView; 

    // Movable Mask 
    UIImage *frameBorder = [UIImage imageNamed:@"semiTransSquare.png"]; 
    maskImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, (frameBorder.size.width/2), (frameBorder.size.height/2))]; 
    maskImageView.image = frameBorder; 

    UIPanGestureRecognizer *panGesture2 = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; 
    [panGesture2 setDelegate:self]; 
    [maskImageView addGestureRecognizer:panGesture2]; 
    UIPinchGestureRecognizer *pinchGesture2 = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)]; 
    [pinchGesture2 setDelegate:self]; 
    [maskImageView addGestureRecognizer:pinchGesture2]; 
    UIRotationGestureRecognizer *rotateGesture2 = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotate:)]; 
    [rotateGesture2 setDelegate:self]; 
    [maskImageView addGestureRecognizer:rotateGesture2]; 

    UITapGestureRecognizer *tapGR =[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTap:)]; 
    [tapGR setDelegate:self]; 
    [tapGR setNumberOfTapsRequired:1]; 
    [maskImageView addGestureRecognizer:tapGR]; 

    [maskImageView setUserInteractionEnabled:YES]; 
    // Add to view to make visible; 
    [self.view addSubview:maskImageView]; 

    // apply layer mask to makskedImageView 
    [self grabTransform:maskImageView]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

- (void)grabTransform:(UIView *)currentView 
{ 
    // build the transform you want 
    CGAffineTransform t = CGAffineTransformIdentity; 
    CGFloat angle = [(NSNumber *)[currentView valueForKeyPath:@"layer.transform.rotation.z"] floatValue]; 
    CGFloat scale = [(NSNumber *)[currentView valueForKeyPath:@"layer.transform.scale"] floatValue]; 
    t = CGAffineTransformConcat(t, CGAffineTransformMakeScale(scale, scale)); 
    t = CGAffineTransformConcat(t, CGAffineTransformMakeRotation(angle)); 
    NSLog(@"angle: %f, scale: %f", angle, scale); 

    // Create a mask layer 
    // Create a mask layer and the frame to determine what will be visible in the view. 
    CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; 
    // CGRect maskRect = currentView.bounds; 
    // Frame works a lot better. 
    CGRect maskRect = currentView.frame; 

    maskRect.origin.x = currentView.frame.origin.x; 
    maskRect.origin.y = currentView.frame.origin.y; 

    // Make a Path friendly transform. 

    CGPoint center = CGPointMake(CGRectGetMidX(currentView.frame), CGRectGetMidY(currentView.frame)); 
    CGAffineTransform transform = CGAffineTransformIdentity; 

    transform = CGAffineTransformTranslate(transform, center.x, center.y); 
    transform = CGAffineTransformScale(transform, scale, scale); 
    transform = CGAffineTransformRotate(transform, angle); 
    transform = CGAffineTransformTranslate(transform, -center.x, -center.y); 

    // Create a path and from the rectangle in it. 
    CGPathRef path = CGPathCreateWithRect(maskRect, &transform); 
    // Set the path to the mask layer. 
    [maskLayer setPath:path]; 
    // Release the path since it's not covered by ARC. 
    CGPathRelease(path); 
    // Set the mask of the view. 
    makskedImageView.layer.mask = maskLayer; 


} 

#pragma mark - Gestures 

-(void)handlePan:(UIPanGestureRecognizer *)recognizer 
{ 
    CGPoint translation = [recognizer translationInView:self.view]; 
    recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, 
             recognizer.view.center.y + translation.y); 
    [recognizer setTranslation:CGPointMake(0, 0) inView:self.view]; 
    [self grabTransform:[recognizer view]]; 
} 

-(void)handlePinch:(UIPinchGestureRecognizer *)recognizer 
{ 
    recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale); 

    recognizer.scale = 1; 
    [self grabTransform:[recognizer view]]; 
} 

-(void)handleRotate:(UIRotationGestureRecognizer *)recognizer 
{ 
    recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation); 
    recognizer.rotation = 0; 
valueForKeyPath:@"layer.transform.rotation"] floatValue]; 
    [self grabTransform:[recognizer view]]; 
} 

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
{ 
    return YES; 
} 

- (void)handleTap:(UIGestureRecognizer *)recognizer 
{ 
    [self grabTransform:[recognizer view]]; 

} 

@end 

加2圖片:Forest.jpg & semiTransSquare.png

現在,當它運行它的作品爲平移,直到我scale.rotate圖像。 (現在旋轉工作感謝其他代碼)。

從我可以告訴規模與中心的工作作爲它成長/縮小的點,其中路徑似乎從根x,y座標伸出。

這可能是由設計(CGPathCreateWithRect per the docs),但我看不到的方式來對轉換適用於CGPath並讓它出現在同一地點的UIImageView「掩模圖像」

性能是一大問題和CIImage的類似解決方案非常滯後,所以想要在CGPath創建圖層掩碼的情況下解決這個問題,如果可能的話,或者一樣快。

我錯過了什麼?歡迎使用iOS 6解決方案。

更新:我發現,從範圍更改爲框架讓我90%的方式出現:

CGRect maskRect = currentView.frame; 

的路徑,現在將匹配該視圖的旋轉和位置。剩下的唯一問題是規模是錯誤的。它匹配原始尺寸,但是如果縮小,那麼它變得太小,或者如果你長大,它會變得太大。看起來規模不是1:1。現在很近。

+0

增加。我覺得這不會那麼難。 :-)讓我知道如果我需要用完整代碼創建一個虛擬應用程序來更清楚地顯示問題。 – Adam21e

+0

如果你添加一個虛擬應用程序,我會仔細看看它。 – algal

回答

0

我不知道我完全理解你對問題的描述,所以一個虛擬應用程序會非常有幫助。但這裏是我現在看到的分析:

你說你有兩個UIImageViews,Background和MaskImage。由此看來,從你的代碼,我知道你想要做的是:

  1. 得到CGPath表示MaskImage的實際形狀,已應用於各種變換後,從點(大概)超級觀點或高於超級觀點。
  2. 使用CGPath定義CAShapeLayer,您將作爲掩膜一些其他觀點的襯裏層,想必背景的UIImageView

上使用。在這種情況下,MaskImage在你的文本對應於你的代碼的currentView (因爲這是你獲得轉換的地方),並且文本中的背景對應於你的代碼的currentImageView(因爲那是你改變圖層蒙版的地方)。對?

如果這一切是正確的,那麼有兩個關鍵問題與您的代碼:

  1. 你想獲得代表currentView的變換形狀的一個CGPath。但是你抓住了currentView.frame。這是錯誤的。 currentView.frame將代表最小的矩形,座標爲currentView.superview,其中可以包含currentView的變形形狀。因此,例如,如果currentView是一個旋轉45度的正方形,那麼currentView.frame仍然是一個正方形,只是一個更大的正方形。相反,你應該做的是獲得currentView.bounds,這是rect,它表示currentView在其自己的座標系中的形狀,從中生成一個路徑,然後將currentView.transform應用到該路徑。

  2. 您不會在代碼或文本中的任何位置指定如何從currentView.superview的座標系映射到MaskImage的座標系。在將形狀應用於MaskImage.layer.mask之前,您還需要執行此操作。

例如,我可以想象其中屏幕被切割成兩個相等的側的應用左,右,其在屏幕的左側呈現的大照片圖像,並且在屏幕的右側它允許您平移,旋轉和縮放黑色矩形的圖像。然後,應用程序將使用右側的黑色矩形來定義一個CAShapeLayer,它被用作左側圖像上的蒙版。這聽起來像你要去的。所以,我要說的是,那你需要爲這個工作步驟的邏輯集是:

  1. 找一個CGPath爲界限黑色矩形的,這將是一個untransfored矩形。
  2. 使用在黑色矩形上應用的相同變換來變換此CGPath。
  3. 在包含屏幕右側的矩形的座標系中表示此CGPath。由於右側和左側是全等的,它現在也在座標系中,可以直接應用到屏幕的左側。
  4. 使用CGPath定義CALayer,將此CALayer應用於表示屏幕左側的視圖,並在該視圖的圖層上調用setNeedsDisplay。

P.S.順便說一下,還有第三個問題。請注意,從技術上講,當向圖層添加.mask時,該圖層不應具有超級圖層。所以你不應該添加一個.mask到已經在視圖層次結構中的UIView的背景層,因爲它會有一個超級層。所以,我相信,你應該做的就是暫時從視圖層次結構中刪除UIView,添加遮罩層,然後將視圖重新添加到視圖層次結構中。

+0

感謝您的回覆。我添加了完整的示例代碼(帶圖像)。使用邊界有所幫助,但當我旋轉或縮放時它仍然會碎片化,但它現在好多了。 – Adam21e

0

你看功能

CGPathCreateCopyByTransformingPath

它需要一個CGRect和一個仿射變換應該實現你在之後。

僅供參考它的iOS 5 +

+0

感謝您的建議,不幸的是沒有奏效。我嘗試使用上面的代碼示例中應用於maskrect變量的t變量或變換變量,它仍然執行相同的操作。如果你確實使用示例代碼來使它工作,請讓我知道我缺少的東西。 – Adam21e

0

你可以使用有效比例因子:

CGFloat zoomScale = sqrtf(powf(currentView.transform.a, 2) + powf(currentView.transform.c, 2)); 

這不等於:在賞金

CGFloat scale = [(NSNumber *)[currentView valueForKeyPath:@"layer.transform.scale"] floatValue];