【问题标题】:Draggable UIButton Snap To a Circle Path可拖动的 UIButton 捕捉到圆形路径
【发布时间】:2025-11-29 10:40:01
【问题描述】:

您好,我想让我的 UIButton 只能围绕我通过绘制矩形创建的圆圈拖动。我可能需要制作一个圆形路径而不是圆形但是我不太确定要采用的方法,因为我是新手。这是我拥有的代码,我只希望将按钮围绕该圆圈或不可见路径拖动。任何帮助或示例都会非常有帮助。谢谢!

编辑:我使用了下面的部分答案,但我不确定如何让它正常工作。我希望它与我创建的圆圈大小相同,因此我很高兴只创建一个圆圈路径并将其放在我创建的圆圈的顶部。

//Button Code
timeSetButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [timeSetButton addTarget:self
                         action:nil
               forControlEvents:UIControlEventTouchDown];
        [timeSetButton setImage:[UIImage imageNamed:@"testButton.png"] forState: UIControlStateNormal];
        timeSetButton.frame = CGRectMake(0,415,50,50);
        [self.view addSubview:timeSetButton];

        //Button Listener
        [timeSetButton addTarget:self action:@selector(wasDragged:withEvent:)
         forControlEvents:UIControlEventTouchDragInside];


//Draggable Button Code
// get the touch
UITouch *touch = [[event touchesForView:timeSetButton] anyObject];

// get delta
CGPoint previousLocation = [touch previousLocationInView:timeSetButton];
CGPoint location = [touch locationInView:timeSetButton];
CGFloat delta_x = location.x - previousLocation.x;
CGFloat delta_y = location.y - previousLocation.y;

// move button
timeSetButton.center = CGPointMake(timeSetButton.center.x + delta_x,
                            timeSetButton.center.y + delta_y);

// enforce constraint on locations, by...

// working out the distance from the centre of the circle
CGPoint vectorFromCentreOfCircle =
CGPointMake(150,150);

CGFloat distanceFromCentreOfCircle = hypotf(vectorFromCentreOfCircle.x, vectorFromCentreOfCircle.y);

// working out what you'd need to multiply that distance by in order
// to get the specified radius
CGFloat correctionMultiplier = 20 / distanceFromCentreOfCircle;

// adjust vector from centre of circle
vectorFromCentreOfCircle.x *= correctionMultiplier;
vectorFromCentreOfCircle.y *= correctionMultiplier;

// move button one more time
timeSetButton.center = CGPointMake(
                    200 + vectorFromCentreOfCircle.x,
                    200 + vectorFromCentreOfCircle.y);

这是圆形

circleView = [[CircleView alloc] initWithFrame:CGRectMake(55, 100, 260, 260)];
        circleView.backgroundColor = [UIColor clearColor];
        [self.view addSubview:circleView];
        [self.view sendSubviewToBack:circleView];

【问题讨论】:

标签: ios objective-c


【解决方案1】:

我实际上也需要同样的东西,并且正在查看您的代码。您实际需要做的是获取实际圆的角度,然后计算所需的 x 和 y。我就是这样做的:

    UIButton *button = (UIButton *) sender;
UITouch *touch = [[event touchesForView:button] anyObject];

//Drawing the circle
CGPoint arcCenter = CGPointMake(385.0f, 700.0f);
CGFloat arcRadius = 140.0f;


// get delta
CGPoint previousLocation = [touch previousLocationInView:button];
CGPoint location = [touch locationInView:button];
CGFloat delta_x = location.x - previousLocation.x;
CGFloat delta_y = location.y - previousLocation.y;


// move button
button.center = CGPointMake(button.center.x + delta_x, button.center.y + delta_y);

CGFloat angle = atan2((button.center.y - arcCenter.y), (button.center.x - arcCenter.x));

button.center = CGPointMake(arcCenter.x + arcRadius * cos(angle), arcCenter.y + arcRadius * sin(angle));

当我向按钮添加拖动时,这给了我实际需要的行为。我使用 Touch Drag Outside 和 Inside 来避免当您将手指从按钮移开太多时按钮停止。希望对你也有帮助。

【讨论】:

    【解决方案2】:

    对于这类事情,在您移动按钮以强制执行它必须位于圆圈上的约束之后,只需添加一点代码就足够了。例如

    // move button
    timeSetButton.center = CGPointMake(button.center.x + delta_x,
                                button.center.y + delta_y);
    
    // enforce constraint on locations, by...
    
    // working out the distance from the centre of the circle
    CGPoint vectorFromCentreOfCircle =
         CGPointMake(timeSetButton.center.x - centreOfCircle.x,
                     timeSetButton.center.x - centreOfCircle.y);
    
    CGFloat distanceFromCentreOfCircle = 
         hypotf(vectorFromCentreOfCircle.x, vectorFromCentreOfCircle.y);
    
    // working out what you'd need to multiply that distance by in order
    // to get the specified radius
    CGFloat correctionMultiplier = radiusOfCircle / distanceFromCentreOfCircle;
    
    // adjust vector from centre of circle
    vectorFromCentreOfCircle.x *= correctionMultiplier;
    vectorFromCentreOfCircle.y *= correctionMultiplier;
    
    // move button one more time
    timeSetButton.center = CGPointMake(
              centreOfCircle.x + vectorFromCentreOfCircle.x,
              centreOfCircle.y + vectorFromCentreOfCircle.y);
    

    【讨论】:

    • CGFloat distanceFromCentreOfCircle = hypotf(vectorFromCentreOfCircle.x, vectorFromCentreOfCircle.y);
    • 谢谢!在 centerOfCircle 我是如何计算的?我需要弄清楚这一点并制作一个 CGPoint 值吗?
    • 同radiusOfCircle?
    • @GrantWilkinson 这取决于您的CircleView 的工作方式。如果我不得不猜测,圆的中心可能是circleView.center,而圆的半径可能至少接近(circleView.frame.size.width * 0.5f)
    【解决方案3】:

    您只需知道 touchPoint 与视图中心的距离即可完成此操作

    我将在您的代码中进行以下修改。看看这是否有效

    - (void)wasDragged:(UIButton *)button withEvent:(UIEvent *)event
    {
        // get the touch
        UITouch *touch = [[event touchesForView:button] anyObject];
    
        // get delta
        CGPoint previousLocation = [touch previousLocationInView:button];
        CGPoint location = [touch locationInView:button];
    
        //calculate center of button in superView
        CGPoint buttonCenter = CGPointMake(button.frame.origin.x+(button.frame.size.width/2.0f),
                                           button.frame.origin.y+(button.frame.size.height/2.0f));
        //calculate the distance of current touchPoint from buttonCenter
        CGFloat diffx = location.x - buttonCenter.x;
        CGFloat diffy = location.y - buttonCenter.y;
        CGFloat distance = sqrtf((diffx*diffx)+(diffy*diffy));
    
        //check if the distance is within the radius of circle.
        //assuming that your button is always a square to make 
        //perfect circle within it.
        CGFloat radius = button.frame.size.width/2.0f;
    
        if(radius >= distance)//this makes a circular check.
        {
          CGFloat delta_x = location.x - previousLocation.x;
          CGFloat delta_y = location.y - previousLocation.y;
    
          // move button
          timeSetButton.center = CGPointMake(button.center.x + delta_x,
                                    button.center.y + delta_y);
        }
    
    }
    

    【讨论】:

    • 圆半径的大小在哪里调整?
    • 在我的代码中,半径由按钮框架的半宽决定。您可以将其更改为任何值。
    最近更新 更多