5

ユーザーがカメラで撮ったばかりの写真を表示するUIImageViewがあります。その画像に、設定されたサイズの透明な可動円を描く必要があります。したがって、ユーザーが画像上で指をドラッグすると、円も一緒に移動します。次に、ユーザーが指の移動を停止すると、円は同じ場所にとどまります。

CAShapeLayerでアップルのドキュメントを読んでいますが、それでも最善の方法がわかりません。UIViewを描画する必要がありますか?

どんな例でも素晴らしいでしょう。ありがとう。

4

1 に答える 1

19

次のコードは、3つのジェスチャを作成します。

  • タップジェスチャは、ビューに円をドロップします(がどのようにCAShapeLayer作成されるかを確認できるようにするため)。

  • パンジェスチャは円を移動します(円内から移動を開始したと仮定します)。と

  • ピンチジェスチャは円のサイズを変更します。

したがって、次のようになります。

#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIGestureRecognizerSubclass.h>

@interface ViewController ()

@property (nonatomic, weak) CAShapeLayer *circleLayer;
@property (nonatomic) CGPoint circleCenter;
@property (nonatomic) CGFloat circleRadius;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    // create tap gesture

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(handleTap:)];
    [self.view addGestureRecognizer:tap];

    // create pan gesture

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self
                                                                          action:@selector(handlePan:)];
    [self.view addGestureRecognizer:pan];

    // create pinch gesture

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(handlePinch:)];
    [self.view addGestureRecognizer:pinch];
}

// Create a UIBezierPath which is a circle at a certain location of a certain radius.
// This also saves the circle's center and radius to class properties for future reference.

- (UIBezierPath *)makeCircleAtLocation:(CGPoint)location radius:(CGFloat)radius
{
    self.circleCenter = location;
    self.circleRadius = radius;

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:self.circleCenter
                    radius:self.circleRadius
                startAngle:0.0
                  endAngle:M_PI * 2.0
                 clockwise:YES];

    return path;
}

// Create a CAShapeLayer for our circle on tap on the screen

- (void)handleTap:(UITapGestureRecognizer *)gesture
{
    CGPoint location = [gesture locationInView:gesture.view];

    // if there was a previous circle, get rid of it

    [self.circleLayer removeFromSuperlayer];

    // create new CAShapeLayer

    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = [[self makeCircleAtLocation:location radius:50.0] CGPath];
    shapeLayer.strokeColor = [[UIColor redColor] CGColor];
    shapeLayer.fillColor = nil;
    shapeLayer.lineWidth = 3.0;

    // Add CAShapeLayer to our view

    [gesture.view.layer addSublayer:shapeLayer];

    // Save this shape layer in a class property for future reference,
    // namely so we can remove it later if we tap elsewhere on the screen.

    self.circleLayer = shapeLayer;
}

// Let's move the CAShapeLayer on a pan gesture (assuming we started
// pan inside the circle).

- (void)handlePan:(UIPanGestureRecognizer *)gesture
{
    static CGPoint oldCenter;

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        // If we're starting a pan, make sure we're inside the circle.
        // So, calculate the distance between the circle's center and 
        // the gesture start location and we'll compare that to the 
        // radius of the circle.

        CGPoint location = [gesture locationInView:gesture.view];
        CGPoint translation = [gesture translationInView:gesture.view];
        location.x -= translation.x;
        location.y -= translation.y;

        CGFloat x = location.x - self.circleCenter.x;
        CGFloat y = location.y - self.circleCenter.y;
        CGFloat distance = sqrtf(x*x + y*y);

        // If we're outside the circle, cancel the gesture.
        // If we're inside it, keep track of where the circle was.

        if (distance > self.circleRadius)
            gesture.state = UIGestureRecognizerStateCancelled;
        else
            oldCenter = self.circleCenter;
    }
    else if (gesture.state == UIGestureRecognizerStateChanged)
    {
        // Let's calculate the new center of the circle by adding the
        // the translationInView to the old circle center.

        CGPoint translation = [gesture translationInView:gesture.view];
        CGPoint newCenter = CGPointMake(oldCenter.x + translation.x, oldCenter.y + translation.y);

        // Update the path for our CAShapeLayer

        self.circleLayer.path = [[self makeCircleAtLocation:newCenter radius:self.circleRadius] CGPath];
    }
}

// Let's resize circle in the CAShapeLayer on a pinch gesture (assuming we have
// a circle layer).

- (void)handlePinch:(UIPinchGestureRecognizer *)gesture
{
    static CGFloat oldCircleRadius;

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        if (self.circleLayer)
            oldCircleRadius = self.circleRadius;
        else
            gesture.state = UIGestureRecognizerStateCancelled;
    }
    else if (gesture.state == UIGestureRecognizerStateChanged)
    {
        CGFloat newCircleRadius = oldCircleRadius * gesture.scale;
        self.circleLayer.path = [[self makeCircleAtLocation:self.circleCenter radius:newCircleRadius] CGPath];
    }
}

@end
于 2013-03-10T16:39:05.307 に答える