これが1つの概念です。指をドラッグし始めた場所から離す場所まで線を引き、指をドラッグしながらアニメーション化します。これを行うには、を作成しCAShapeLayer
、指を動かしながらリセットしpath
ます。
これは、基本的な考え方を示しているはずです。
- (void)viewDidLoad {
[super viewDidLoad];
UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
[self.view addGestureRecognizer:gesture];
}
- (CAShapeLayer *)createShapeLayer:(UIView *)view {
CAShapeLayer *shapeLayer = [[CAShapeLayer alloc] init];
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.strokeColor = [UIColor redColor].CGColor;
shapeLayer.lineWidth = 3.0;
[view.layer addSublayer:shapeLayer];
return shapeLayer;
}
- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture {
static CAShapeLayer *shapeLayer;
static CGPoint origin;
if (gesture.state == UIGestureRecognizerStateBegan) {
shapeLayer = [self createShapeLayer:gesture.view];
origin = [gesture locationInView:gesture.view];
} else if (gesture.state == UIGestureRecognizerStateChanged) {
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:origin];
CGPoint location = [gesture locationInView:gesture.view];
[path addLineToPoint:location];
shapeLayer.path = path.CGPath;
} else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateFailed ||
gesture.state == UIGestureRecognizerStateCancelled) {
shapeLayer = nil;
}
}
または、Swift 3:
override func viewDidLoad() {
super.viewDidLoad()
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
view.addGestureRecognizer(pan)
}
private func createShapeLayer(for view: UIView) -> CAShapeLayer {
let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.red.cgColor
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)
return shapeLayer
}
private var shapeLayer: CAShapeLayer!
private var origin: CGPoint!
func handlePan(_ gesture: UIPanGestureRecognizer) {
if gesture.state == .began {
shapeLayer = createShapeLayer(for: gesture.view!)
origin = gesture.location(in: gesture.view)
} else if gesture.state == .changed {
let path = UIBezierPath()
path.move(to: origin)
path.addLine(to: gesture.location(in: gesture.view))
shapeLayer.path = path.cgPath
} else if gesture.state == .ended || gesture.state == .failed || gesture.state == .cancelled {
shapeLayer = nil
}
}
を使用しないCAShapeLayer
が、以前のパスを追跡したい場合は、それらの古いパスの配列を維持し、すべての古いパスで構成されるパスを作成する必要があります。たとえば、次のようになります。
@interface CustomView ()
@property (nonatomic) CGPoint originPoint;
@property (nonatomic) CGPoint currentPoint;
@property (nonatomic) NSMutableArray *previousPaths;
@end
@implementation CustomView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self configure];
}
return self;
}
- (id)init {
return [self initWithFrame:CGRectZero];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self configure];
}
return self;
}
- (void)configure {
_previousPaths = [[NSMutableArray alloc] init];
}
- (void)drawRect:(CGRect)rect {
[[UIColor redColor] setStroke];
UIBezierPath *drawPath = [UIBezierPath bezierPath];
drawPath.lineCapStyle = kCGLineCapRound;
drawPath.miterLimit = 0;
drawPath.lineWidth = 3.0;
for (UIBezierPath *path in self.previousPaths)
[drawPath appendPath:path];
UIBezierPath *path = [self pathForCurrentLine];
if (path)
[drawPath appendPath:path];
[drawPath stroke];
}
- (UIBezierPath *)pathForCurrentLine {
if (CGPointEqualToPoint(self.originPoint, CGPointZero) && CGPointEqualToPoint(self.currentPoint, CGPointZero))
return nil;
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:self.originPoint];
[path addLineToPoint:self.currentPoint];
return path;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.originPoint = [[touches anyObject] locationInView:self];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([event respondsToSelector:@selector(predictedTouchesForTouch:)]) {
touch = [[event predictedTouchesForTouch:touch] lastObject] ?: touch;
}
self.currentPoint = [touch locationInView:self];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
self.currentPoint = [[touches anyObject] locationInView:self];
[self.previousPaths addObject:[self pathForCurrentLine]];
self.originPoint = self.currentPoint = CGPointZero;
[self setNeedsDisplay];
}
@end