3

原点からの距離に応じて自動的にサイズが変わる直線を指で描きたい。

したがって、中央の画面に触れて指をスライドさせると、指が画面上を移動するときに、線が「伸びる」ように見え、原点を中心に回転します。指を離すとき。宛先ポイントは、線を完成させて作成する必要があります。画面上で指をドラッグして「描画」することはできますが、それは私がやりたいことではありません。

UIBeizerPath moveToPointが役立つと思いましたが、それは物事を台無しにするだけです。

私は何が間違っているのですか?

- (id)initWithFrame:(CGRect)frame
{
     //default line properties
    myPath=[[UIBezierPath alloc]init];
    myPath.lineCapStyle=kCGLineCapRound;
    myPath.miterLimit=0;
    myPath.lineWidth=lineWidth;
    brushPattern=[UIColor blackColor];
 }



-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint curPoint = [[touches anyObject] locationInView:self];

    lastPoint = curPoint;

    [myPath moveToPoint:lastPoint];
    [pathArray addObject:myPath];
    [self setNeedsDisplay];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{

    CGPoint curPoint = [[touches anyObject] locationInView:self];

    myPath.lineWidth=lineWidth;
    brushPattern=[UIColor redColor]; //red to show it hasn't been added yet.
    [myPath moveToPoint:tempPoint];
    [self setNeedsDisplay];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

    CGPoint curPoint = [[touches anyObject] locationInView:self];

    myPath.lineWidth=lineWidth;

    brushPattern=[UIColor blackColor]; //finalize the line with black color
    [myPath addLineToPoint:curPoint];
    [self setNeedsDisplay];
}
4

2 に答える 2

4

これが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
于 2013-01-07T20:02:51.750 に答える
2

UIBezierPathは、指示からパスを構築しています。ペンを想像してみてください。「moveToPoint:」と言うと、ペンがそのポイントに移動します。「lineToPoint:」と言うと、ペンを下に置き、現在の場所から新しいポイントに移動します。等々。

希望する効果を得るには、タッチが移動するたびに新しいパスを作成し、元のポイントから現在のタッチ位置まで線を引く必要があります。

于 2013-01-07T19:35:17.860 に答える