我有一个 UIImageView 显示用户刚刚用相机拍摄的照片。在该图像上,我需要绘制一个设置大小的透明可移动圆圈。因此,当用户在图像上拖动手指时,圆圈会随之移动。然后,如果用户停止移动他们的手指,圆圈会停留在同一个地方。
我一直在阅读CAShapeLayer上的苹果文档,但我仍然不确定最好的方法,我应该绘制 UIView 吗?
任何例子都会很棒。谢谢。
我有一个 UIImageView 显示用户刚刚用相机拍摄的照片。在该图像上,我需要绘制一个设置大小的透明可移动圆圈。因此,当用户在图像上拖动手指时,圆圈会随之移动。然后,如果用户停止移动他们的手指,圆圈会停留在同一个地方。
我一直在阅读CAShapeLayer上的苹果文档,但我仍然不确定最好的方法,我应该绘制 UIView 吗?
任何例子都会很棒。谢谢。
以下代码创建三个手势:
点击手势会在视图上放置一个圆圈(这样您就可以看到它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