Draw line between two movable uiviews

2019-05-24 12:38发布

问题:

I have a "scrollview" with nodes (UIViews) that can be dragged around. I am trying to draw edges between selected UIViews with a "calayer", but I can't figure out how to redraw the line when a views position have changed.

In my viewController class I add the edge between first and second in the nodes array as:

EdgeLayer *edge = [[EdgeLayer alloc]init];
edge.delegate = self;
edge.strokeColor = [UIColor colorWithWhite:0.25 alpha:1.0];
edge.strokeWidth = 0.5;
edge.startNode = [nodes objectAtIndex:0];
edge.endNode = [nodes objectAtIndex:1];
edge.frame = scrollView.bounds;
[scrollView.layer addSublayer:edge];
[edge setNeedsDisplay];

EdgeLayer.h:

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

@interface EdgeLayer : CALayer
@property (nonatomic, strong) UIColor *fillColor;
@property (nonatomic) CGFloat strokeWidth;
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic) UIView *startNode;
@property (nonatomic) UIView *endNode;
@end

EdgeLayer.m:

#import "EdgeLayer.h"
#import "NodeView.h"

@implementation EdgeLayer

@synthesize fillColor, strokeColor, strokeWidth;
- (id)init {
    self = [super init];
    if (self) {
    self.fillColor = [UIColor grayColor];
    self.strokeColor = [UIColor blackColor];
    self.strokeWidth = 1.0;
    [self setNeedsDisplay];
}

return self;
}

- (void) setStartNode:(NodeView*)startNode
{
     _startNode = startNode;
     [self setNeedsDisplay];
}

- (void) setEndNode:(NodeView*)endNode
{
    _endNode = endNode;
    [endNode addObserver:self forKeyPath:@"endNode" options:NSKeyValueObservingOptionNew context:nil];
    [self setNeedsDisplay];
 }

-(id)initWithLayer:(id)layer
{
    self = [super initWithLayer:layer];
    return self;
}

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:    (NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"endNode"] )
    {
    // process here
    }
    NSLog(@"View changed its geometry");
}

- (void)drawInContext:(CGContextRef)ctx
{
    NSLog(@"DRAW");

    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextSetLineWidth(ctx, 2);
    CGContextMoveToPoint(ctx, _startNode.center.x, _startNode.center.y);
    CGContextAddLineToPoint(ctx, _endNode.center.x, _endNode.center.y);
    CGContextStrokePath(ctx);
}
@end

This adds a line from the first and second nodes center position. I have tried to add an observer for the end node, but I don't think that I'm doing it right. I can't trigger the observeValueForKeyPath method. My guess is that I added the observer in the wrong place.

回答1:

The problem is not where you add the observer, but what you're tying to observe -- you're using endNode as the keyPath on endNode which won't work (endNode isn't changing as you drag anyway). The property of endNode that you want to observe is the center.

You only then need to change the keyPath you're observing to "center", and change your implementation of observeValueForKeyPath:ofObject:change:context: like so,

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"center"] ) [self setNeedsDisplay];
}

I tested this by adding a pan gesture recognizer to one of the nodeViews, and the line connecting the two nodes was updated appropriately as I dragged.