なぜこれが機能しないのか理解できませんが、私はまだiOSにかなり慣れていません。
私は2つの別々のUIImageViewを持っています
- 「背景」。これは、画像の一部だけが見えるようにレイヤー マスクが適用される画像です。
- 「マスク イメージ」は、回転、パン、ピンチ ズームが可能な独自の独立したイメージです。回転/スケールのコードは正常に機能し、標準コードです。
私がやろうとしているのは、「マスク イメージ」の現在の位置/回転/スケールに一致する CGPath を作成することです。
これは、「マスク イメージ」の場所を取得し、レイヤー マスクとして使用する CGPAth を作成するコードです。
Xcode に移動して新しい「Single View Application」プロジェクトを作成する場合、ここに ViewController の完全なコピー ペーストがあります。
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 ) が、変換を CGPath に適用し、それを UIImageView 'Mask Image' と同じ場所に表示する方法がわかりません
パフォーマンスは大きな問題であり、CIImage を使用した同様のソリューションは非常に遅いため、可能であれば CGPath でレイヤー マスクを作成するか、同じくらい高速な方法でこれを解決したいと考えています。
私は何が欠けていますか?iOS 6 のみのソリューションに最適です。
更新:境界からフレームに変更すると、90% の方法が得られることがわかりました。
CGRect maskRect = currentView.frame;
パスはビューの回転と位置に一致します。残っている唯一の問題は、スケールが間違っていることです。元のサイズで合っていますが、縮めば小さくなり、伸びれば大きくなります。縮尺は 1:1 ではないようです。今とても近い。