iOS拖动形状固定到中心

时间:2014-10-02 12:23:44

标签: ios objective-c

从这篇文章Drag UIView around Shape Comprised of CGMutablePaths开始下一步,我试图在一端添加一条固定在pathLayer_中心的线,另一端与圆形对象一起拖动(handleView_中的circleLayer) )在路径上(图-8)。

example

该行在(void)initHandleView中有自己的层和视图以及路径。

首先:我无法让线路通过路径中心_Layer_:

- (void)viewDidLoad {
[super viewDidLoad];
[self initPathLayer];
[self initHandleView];
[self initHandlePanGestureRecognizer];
}


- (void)initPathLayer {
pathLayer_ = [CAShapeLayer layer];
pathLayer_.lineWidth = 1;
pathLayer_.fillColor = nil;
pathLayer_.strokeColor = [UIColor lightGrayColor].CGColor;
pathLayer_.lineCap = kCALineCapButt;
pathLayer_.lineJoin = kCALineJoinRound;
pathLayer_.frame = self.view.bounds;
pathLayerCenter_ = CGPointMake(CGRectGetMidX(pathLayer_.frame), CGRectGetMidY(pathLayer_.frame));
[self.view.layer addSublayer:pathLayer_];
}


- (void)initHandleView {
handlePathPointIndex_ = 0;
CGRect rect = CGRectMake(0, 0, 30, 30);
CAShapeLayer *circleLayer = [CAShapeLayer layer];
circleLayer.fillColor = [UIColor redColor].CGColor;
circleLayer.strokeColor = [UIColor redColor].CGColor;
circleLayer.lineWidth = 2;
UIBezierPath *circlePath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(rect, circleLayer.lineWidth, circleLayer.lineWidth)];
circleLayer.frame = rect;
circleLayer.path = circlePath.CGPath;
handleView_ = [[UIView alloc] initWithFrame:rect];

CGRect lineRect = CGRectMake(0,0,CGRectGetMaxX([[UIScreen mainScreen] bounds]), CGRectGetMaxY([[UIScreen mainScreen] bounds]));
CGPoint center = CGPointMake(CGRectGetMidX(pathLayer_.frame), CGRectGetMidY(pathLayer_.frame));
lineView_ = [[UIView alloc] initWithFrame:lineRect];
CAShapeLayer *lineLayer = [CAShapeLayer layer];
lineLayer.fillColor = [UIColor blueColor].CGColor;
lineLayer.strokeColor = [UIColor blueColor].CGColor;
lineLayer.lineWidth = 2;
lineLayer.frame = self.view.bounds;
UIBezierPath *linePath = [UIBezierPath bezierPath];
CGPoint circlePoint = CGPointMake(handleView_.center.x, handleView_.center.y);
[linePath moveToPoint:center]; //Center
[linePath addLineToPoint:circlePoint];
[linePath moveToPoint:circlePoint]; //Handle
lineLayer.path = linePath.CGPath;

[handleView_.layer insertSublayer:circleLayer above:handleView_.layer];
[handleView_.layer insertSublayer:lineLayer above:handleView_.layer];
//  handleView_.layer.masksToBounds = YES;
float direction = DEGREES_TO_RADIANS(10);

CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(direction);
[handleView_ setTransform:rotationTransform];


[self.view addSubview:lineView_];
[self.view addSubview:handleView_];

}

第二:我不确定我是否使用PanGesturerecognizer做正确的事情:

- (void)handleWasPanned:(UIPanGestureRecognizer *)recognizer {
switch (recognizer.state) {
    case UIGestureRecognizerStateBegan: {
        desiredHandleCenter_ = handleView_.center;
        break;
    }

    case UIGestureRecognizerStateChanged:
    case UIGestureRecognizerStateEnded:
    case UIGestureRecognizerStateCancelled: {
        CGPoint translation = [recognizer translationInView:self.view];
        desiredHandleCenter_.x += translation.x;
        desiredHandleCenter_.y += translation.y;
        [self moveHandleTowardPointAndRotateLine:desiredHandleCenter_];
        break;
    }

    default:
        break;
}

[recognizer setTranslation:CGPointZero inView:self.view];
}

- (void)moveHandleTowardPointAndRotateLine:(CGPoint)point {
CGFloat earlierDistance = [self distanceToPoint:point ifHandleMovesByOffset:-1];
CGFloat currentDistance = [self distanceToPoint:point ifHandleMovesByOffset:0];
CGFloat laterDistance = [self distanceToPoint:point ifHandleMovesByOffset:1];
if (currentDistance <= earlierDistance && currentDistance <= laterDistance)
    return;

NSInteger step;
CGFloat distance;
if (earlierDistance < laterDistance) {
    step = -1;
    distance = earlierDistance;
} else {
    step = 1;
    distance = laterDistance;
}

NSInteger offset = step;
while (true) {
    NSInteger nextOffset = offset + step;
    CGFloat nextDistance = [self distanceToPoint:point ifHandleMovesByOffset:nextOffset];
    if (nextDistance >= distance)
        break;
    distance = nextDistance;
    offset = nextOffset;
}
handlePathPointIndex_ += offset;

// Make one end of the line move with handle (point) while the other is pinned to center of pathLayer_ (ie. in figure8 its the cross point, in a circle it's center)

//CGFloat rot = [self getTouchAngle:point];
CGFloat rot = atan2f((point.x - pathLayerCenter_.x), -(point.y - pathLayerCenter_.y));
handleView_.layer.transform = CATransform3DMakeRotation(rot, 0., 0., 1.);
[self layoutHandleView];
}

1 个答案:

答案 0 :(得分:1)

我只是会忽略您的代码并告诉您我如何修改原始答案以添加您想要的行。

首先,我将为该行使用专用的形状图层,因此我将添加一个实例变量来引用该行图层:

@implementation ViewController {
    CAShapeLayer *lineLayer_; // NEW!!!
    UIBezierPath *path_;
    CAShapeLayer *pathLayer_;
    etc.

我在加载视图时需要初始化线图层:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initPathLayer];
    [self initHandleView];
    [self initHandlePanGestureRecognizer];
    [self initLineLayer]; // NEW!!!
}

- (void)initLineLayer {
    lineLayer_ = [CAShapeLayer layer];
    lineLayer_.lineWidth = 1;
    lineLayer_.fillColor = nil;
    lineLayer_.strokeColor = [UIColor redColor].CGColor;
    lineLayer_.lineCap = kCALineCapRound;
    lineLayer_.lineJoin = kCALineJoinRound;
    [self.view.layer addSublayer:lineLayer_];
}

当我布置顶级视图时(首次显示和旋转时),我需要布置线条图层:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    [self createPath];
    [self createPathPoints];
    [self layoutPathLayer];
    [self layoutHandleView];
    [self layoutLineLayer]; // NEW!!!
}

- (void)layoutLineLayer {
    lineLayer_.frame = self.view.bounds;
    CGRect bounds = self.view.bounds;
    CGPoint start = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    CGPoint end = pathPoints_[handlePathPointIndex_];
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:start];
    [path addLineToPoint:end];
    lineLayer_.path = path.CGPath;
}

最后,每当我更新句柄时,我需要再次布局线图层(以更新其路径):

- (void)moveHandleTowardPoint:(CGPoint)point {
    // I have omitted most of this method body for brevity.
    // Just copy it from the original answer.

    ...
    ...

    handlePathPointIndex_ += offset;
    [self layoutHandleView];
    [self layoutLineLayer]; // NEW!!!
}

结果:

enter image description here