1

なぜこれが機能しないのか理解できませんが、私はまだiOSにかなり慣れていません。

私は2つの別々のUIImageViewを持っています

  1. 「背景」。これは、画像の一部だけが見えるようにレイヤー マスクが適用される画像です。
  2. 「マスク イメージ」は、回転、パン、ピンチ ズームが可能な独自の独立したイメージです。回転/スケールのコードは正常に機能し、標準コードです。

私がやろうとしているのは、「マスク イメージ」の現在の位置/回転/スケールに一致する 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 ではないようです。今とても近い。

4

3 に答える 3

0

問題の説明を完全に理解しているかどうかわからないので、ダミーアプリが非常に役立ちます. しかし、これが私が今見ることができるものからの私の分析です:

Background と MaskImage の 2 つの UIImageView があるとします。これから、そしてあなたのコードから、あなたがやりたいことは次のとおりです。

  1. (おそらく)スーパービューまたはスーパービューよりも上位の観点から、さまざまな変換が適用された後、MaskImage の実​​際の形状を表す CGPath を取得します。
  2. その CGPath を使用して CAShapeLayer を定義します。これは、他のビュー、おそらく Background UIImageView のバッキング レイヤーのマスクとして使用します。

その場合、テキスト内の MaskImage はコードに対応しcurrentView(変換を取得する場所であるため)、テキスト内の Background はコードに対応しますcurrentImageView(レイヤーのマスクを変更する場所であるため)。右?

すべてが正しければ、コードには 2 つの重要な問題があります。

  1. currentView の変換された形状を表す CGPath を取得します。しかし、あなたはつかんでいますcurrentView.frame。これは間違っています。currentView.frameの座標でcurrentView.superview、currentView の変換された形状を含むことができる最小の四角形を表します。したがって、たとえば、 currentView が 45 度回転した正方形の場合、 currentView.frame は正方形のままで、正方形が大きくなっただけです。代わりに、取得する必要がありますcurrentView.bounds。これは、独自の座標系で currentView の形状を表す rect であり、そこからパスを生成し、currentView.transformそのパスに適用します。

  2. コードまたはテキストのどこにも、currentView.superview座標系から MaskImage の座標系にマップする方法を指定しません。また、形状を MaskImage.layer.mask に適用する前にこれを行う必要があります。

たとえば、画面が左右の 2 つの等しい辺にカットされ、画面の左側に大きな写真画像が表示され、画面の右側にパン、回転できるアプリケーションを想像できます。 、黒い四角形の画像をスケーリングします。次に、アプリは右側の黒い四角形を使用して CAShapeLayer を定義し、左側の画像にマスクとして適用されます。これはあなたがしようとしていることのように聞こえます。つまり、これが機能するために必要な一連の論理的な手順は次のとおりです。

  1. 変換されていない四角形になる黒い四角形の境界のCGPath を取得します。
  2. この CGPath を、同じ変換を黒い四角形に適用して変換します。
  3. 画面の右側だけを含む rect の座標系でこの CGPath を表します。右辺と左辺は合同であるため、画面の左辺に直接適用できる座標系にもなりました。
  4. CGPath を使用して CALayer を定義し、この CALayer を画面の左側を表すビューに適用し、そのビューのレイヤーで setNeedsDisplay を呼び出します。

PS ところで、3 つ目の問題があります。技術的には、レイヤーに .mask を追加する場合、そのレイヤーにスーパーレイヤーを含めないでください。したがって、スーパーレイヤーがあるため、既にビュー階層にある UIView のバッキングレイヤーに .mask を追加しないでください。したがって、ビュー階層から UIView を一時的に削除し、マスク レイヤーを削除してから、ビューをビュー階層に再度追加します。

于 2013-01-18T12:23:17.027 に答える
0

関数を見たことがありますか

CGPathCreateCopyByTransformingPath?

それはCGRectあなたが求めているものを達成するはずの と アフィン変換を必要とします。

参考までに、iOS 5 +

于 2013-03-21T21:05:10.263 に答える